home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / irsim-ca.2 / irsim-ca / irsim-cap-9.2 / src / irsim / rsim.c < prev    next >
C/C++ Source or Header  |  1995-11-03  |  88KB  |  3,971 lines

  1. /* 
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     ********************************************************************* 
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include "defs.h"
  17. #include "net.h"
  18. #include "globals.h"
  19.  
  20. /* front end for mos simulator -- Chris Terman (6/84) */
  21. /* sunbstantial changes: Arturo Salz (88) */
  22.  
  23. #define    LSIZE        1000000    /* max size of command line (in chars) */
  24. #define    MAXARGS        50000    /* maximum number of command-line arguments */
  25. #define    CMDTBLSIZE    64    /* size of command hash-table */
  26. #define    MAXCOL        80    /* maximum width of print line */
  27.  
  28.  
  29. #define    ITERATOR_START    '{'
  30. #define    ITERATOR_END    '}'
  31.  
  32. #define    SIZEOF( X )    ( (int) sizeof( X ) )
  33.  
  34.  
  35. typedef struct _Cmd
  36.   {
  37.     char         *name;            /* name of this command */
  38.     int          (*handler)();        /* handler for this command */
  39. /* Don't skimp on the space here PLEASE. It causes problems on
  40. machines where a -short- is just 16 bits (most machines) */
  41. #if 1
  42.     int        nmin, nmax;        /* min and max number of arguments */
  43. #else
  44.     short        nmin, nmax;        /* min and max number of arguments */
  45. #endif
  46.     char         *help;            /* command description */
  47.     struct _Cmd  *next;            /* list of commands in bucket */
  48.   } Command;
  49.  
  50.  
  51. typedef struct _Path
  52.   {
  53.     struct _Path  *next;
  54.     char          name[1];
  55.   } Path;
  56.  
  57.  
  58. typedef struct sequence *sptr;
  59.  
  60. typedef struct sequence
  61.   {
  62.     sptr    next;            /* next vector in linked list */
  63.     int     which;            /* 0 => node; 1 => vector */
  64.     union
  65.       {
  66.     nptr  n;
  67.     bptr  b;
  68.       } ptr;            /* pointer to node/vector */
  69.     int     vsize;            /* size of each value */
  70.     int     nvalues;            /* number of values specified */
  71.     char    values[1];            /* array of values */
  72.   } sequence;
  73.  
  74.  
  75. private    Command    *cmdtbl[ CMDTBLSIZE ];    /* command hash-table */
  76.  
  77. private    Bits    *blist = NULL;        /* list of vectors */
  78.  
  79. private    sptr    slist = NULL;        /* list of sequences */
  80. private    int    maxsequence = 0;    /* longest sequence defined */
  81.  
  82. private    sptr    clock = NULL;        /* vectors which make up clock */
  83. private    int    maxclock = 0;        /* longest clock sequence defined */
  84.  
  85. private    iptr    wlist = NULL;        /* list of nodes to be displayed */
  86. private    iptr    wvlist = NULL;        /* list of vectors to be displayed */
  87.  
  88. private    char    *filename;        /* current input file */
  89. private    int    lineno = 0;        /* current line number */
  90. private    int    column = 0;        /* current output column */
  91. private    int    stoped_state = FALSE;    /* have we stoped ? */
  92.                     
  93. private    Path    *cmdpath = NULL;    /* search path for cmd files */
  94.  
  95. private    long    stepsize = 1000;    /* simulation step, in Delta's */
  96. private    int    dcmdfile = 0;        /* display commands read from file */
  97. private    int    ddisplay = 1;        /* if <>0 run "d" at end of step */
  98.  
  99. private    char    *targv[ MAXARGS ];    /* array of tokens on command line */
  100. private    int    targc;            /* number of args on command line */
  101. private    char    wildCard[ MAXARGS ];    /* set if corresponding arg has '*' */
  102. private    char    plus_minus[] = "+";    /* see apply() below */
  103. private    char    potchars[] = "luxh.";    /* set of potential characters */
  104.  
  105. private    char    *first_file = NULL;    /* basename of network file read-in */
  106.  
  107. public    int    count_InTrans = FALSE;    /* count INPUT trans. (PEL 4/20/93) */
  108. public    int    analyzerON = FALSE;    /* set when analyzer is running */
  109. public    long    sim_time0 = 0;        /* starting time (see flush_hist) */
  110. public    FILE    *logfile = NULL;    /* log file of transactions */
  111. public    FILE    *caplogfile = NULL;    /* log file of cap transitions */
  112. public    float    totpower = 0;        /* indicative of total power of chip */
  113. public  float   vsupply = 5.0;        /* supply voltage for pwr estimation */
  114. public  float   capstarttime = 0.0;
  115. public  float   capstoptime = 0.0;
  116. public  float    captime = 0.0;
  117. public  float    powermult = 0.0;    /* to do power estimate in milliWatts */
  118. public    float    GndCap = 0;        /* capacitance of the ground rail */
  119. public    float    VddCap = 0;        /* capacitance of the power rail */
  120.  
  121.     /* forward references */
  122. private    int    expand(), input();
  123. private    void    shift_args();
  124.  
  125. private    char    not_in_stop[] = "Can't do that while stoped, try \"C\"\n";
  126.  
  127.  
  128. /* 
  129.  * Parse line into tokens, filling up targv and WildCard, and setting 'targc'
  130.  */
  131. private int parse_line( line, bufsize )
  132.   register char  *line;
  133.   int            bufsize;
  134.   {
  135.     char           *extra;
  136.     register int   i;
  137.     register char  ch;
  138.     char           wc;            /* wild card indicator */
  139.  
  140.     /* extra storage comes out of unused portion of line buffer */
  141.     i = strlen( line ) + 1;
  142.     bufsize -= i;
  143.     extra = &line[i];
  144.     targc = 0;
  145.     while( i = *line++ )
  146.       {
  147.         /* skip past white space */
  148.     if( i <= ' ' )
  149.         continue;
  150.  
  151.         /* found start of new argument */
  152.     if( targc == 0 and i == '|' )
  153.       {
  154.         targc = 0;        /* comment line, stop now */
  155.         return;
  156.       }
  157.  
  158.         /* remember where argument begins */
  159.     if( targc >= MAXARGS )
  160.       {
  161.         error( filename, lineno, "too many arguments in command\n" );
  162.         targc = 0;
  163.         return;
  164.       }
  165.     else
  166.         targv[targc++] = --line;
  167.  
  168.       /* skip past text of argument, terminate with null character.
  169.        * While scanning argument remember if we see a "{" which marks
  170.        * the possible beginning of an iteration expression.
  171.        */
  172.  
  173.     wc = FALSE;
  174.     i = 0;
  175.     while( (ch = *line) > ' ' )
  176.       {
  177.         if( ch == '*' )
  178.         wc = TRUE;
  179.         else if( ch == ITERATOR_START )
  180.         i = 1;
  181.         line++;
  182.       }
  183.     *line++ = '\0';
  184.  
  185.       /* if the argument might contain one or more iterators, process
  186.        * it more carefully...
  187.        */
  188.     if( i == 1 )
  189.       {
  190.         if( expand( targv[--targc], &extra, &bufsize, wc ) )
  191.           {
  192.         targc = 0;
  193.         return;
  194.           }
  195.       }
  196.     else
  197.         wildCard[targc - 1] = wc;
  198.       }
  199.   }
  200.  
  201.  
  202. /* 
  203.  * Given a text string, expand any iterators it contains.  For example, the
  204.  * string "out.{1:10}" expands into ten arguments "out.1", ..., "out.10".
  205.  * The string can contain multiple iterators which will be expanded
  206.  * independently, e.g., "out{1:10}{1:20:2}" expands into 100 arguments.
  207.  * Buffer and bufsize describe a byte buffer which can be used for expansion.
  208.  * Return 0 if expansion succeeds, 1 otherwise.
  209.  */
  210. private int expand( string, buffer, bufsize, wc )
  211.   register char  *string;
  212.   char           **buffer;
  213.   int            *bufsize;
  214.   char           wc;
  215.   {
  216.     register char  *p;
  217.     char           prefix[100], index[256];
  218.     int            start, stop, nstep, length;
  219.  
  220.     /* copy string until we reach beginning of iterator */
  221.     p = prefix;
  222.     length = 0;
  223.     while( *string )
  224.       {
  225.     if( *string == ITERATOR_START )
  226.       {
  227.         *p = 0;
  228.         goto gotit;
  229.       }
  230.     *p++ = *string++;
  231.       }
  232.     *p = 0;
  233.  
  234.     /* if we get here, there was no iterator in the string, so save what
  235.      * we have as another argument.
  236.      */
  237.     length = strlen( prefix ) + 1;
  238.     if( length > *bufsize )
  239.       {
  240.     error( filename, lineno, "too many arguments in command\n" );
  241.     return( 1 );
  242.       }
  243.     (void) strcpy( *buffer, prefix );
  244.     wildCard[targc] = wc;
  245.     targv[targc++] = *buffer;
  246.     *bufsize -= length;
  247.     *buffer += length;
  248.     return( 0 );
  249.  
  250.     /* gobble down iterator */
  251.   gotit :
  252.     start = 0;
  253.     stop = 0;
  254.     nstep = 0;
  255.     for( string += 1; *string >= '0' and *string <= '9'; string += 1 )
  256.     start = start * 10 + *string - '0';
  257.     if( *string != ':' )
  258.     goto err;
  259.     for( string += 1; *string >= '0' and *string <= '9'; string += 1 )
  260.     stop = stop * 10 + *string - '0';
  261.     if( *string == ITERATOR_END )
  262.     goto done;
  263.     if( *string != ':' )
  264.     goto err;
  265.     for( string += 1; *string >= '0' and *string <= '9'; string += 1 )
  266.     nstep = nstep * 10 + *string - '0';
  267.     if( *string == ITERATOR_END )
  268.     goto done;
  269.  
  270.   err :
  271.     error( filename, lineno, "syntax error in name iterator" );
  272.     return( 1 );
  273.  
  274.   done :    /* suffix starts just past '}' which terminates iterator */
  275.     string += 1;
  276.  
  277.     /* figure out correct step size */
  278.     if( nstep == 0 )
  279.     nstep = 1;
  280.     else if( nstep < 0 )
  281.     nstep = -nstep;
  282.     if( start > stop )
  283.     nstep = -nstep;
  284.  
  285.     /* expand the iterator */
  286.     while( (nstep > 0 and start <= stop) or (nstep < 0 and start >= stop) )
  287.       {
  288.     (void) sprintf( index, "%s%d%s", prefix, start, string );
  289.     if( expand( index, buffer, bufsize, wc ) )
  290.         return( 1 );
  291.     start += nstep;
  292.       }
  293.     return( 0 );
  294.   }
  295.  
  296.  
  297. /*
  298.  * Apply given function to each argument on the command line.
  299.  * Arguments are checked first to ensure they are the name of a node or
  300.  * vector; wild-card patterns are allowed as names.
  301.  * Either 'fun' or 'vfunc' is called with the node/vector as 1st argument:
  302.  *    'fun' is called if name refers to a node.
  303.  *    'vfun' is called if name refers to a vector.  If 'vfun' is NULL
  304.  *    then 'fun' is called on each node of the vector.
  305.  * The parameter (2nd argument) passed to the specified function will be:
  306.  *    If 'arg' is the special constant 'plus_minus' then
  307.  *        if the name is preceded by a '-' pass a pointer to '-'
  308.  *        otherwise pass a pointer to '+'.
  309.  *    else 'arg' is passed as is.
  310.  */
  311. private void apply( fun, vfun, arg )
  312.   int   (*fun)(), (*vfun)();
  313.   char  *arg;
  314.   {
  315.     register char  *p, *flag;
  316.     register bptr  b;
  317.     register int   i, j, found;
  318.  
  319.     for( i = 1; i < targc; i += 1 )
  320.       {
  321.     p = targv[i];
  322.     if( arg == plus_minus )
  323.       {
  324.         if( *p == '-' )
  325.           {
  326.         flag = p;
  327.         p += 1;
  328.           }
  329.         else
  330.         flag = plus_minus;
  331.       }
  332.     else
  333.         flag = arg;
  334.  
  335.     found = 0;
  336.     if( wildCard[i] )
  337.       {
  338.         for( b = blist; b != NULL; b = b->next )
  339.         if( str_match( p, b->name ) )
  340.           {
  341.             if( vfun != NULL )
  342.             (*vfun)( b, flag );
  343.             else
  344.             for( j = 0; j < b->nbits; j += 1 )
  345.                 (*fun)( b->nodes[j], flag );
  346.             found = 1;
  347.           }
  348.         found += match_net( p, fun, flag );
  349.       }
  350.     else
  351.       {
  352.         nptr  n = find( p );
  353.  
  354.         if( n != NULL )
  355.         found += (*fun)( n, flag );
  356.         else
  357.           {
  358.         for( b = blist; b != NULL; b = b->next )
  359.             if( str_eql( p, b->name ) == 0 )
  360.               {
  361.             if( vfun != NULL )
  362.                 (*vfun)( b, flag );
  363.             else
  364.                 for( j = 0; j < b->nbits; j += 1 )
  365.                 (*fun)( b->nodes[j], flag );
  366.             found = 1;
  367.             break;
  368.               }
  369.           }
  370.       }
  371.     if( found == 0 )
  372.         error( filename, lineno, "%s: No such node or vector\n", p );
  373.       }
  374.   }
  375.  
  376.  
  377. /*
  378.  * map a character into one of the potentials that a node can be set/compared
  379.  */
  380. private int ch2pot( ch )
  381.   char  ch;
  382.   {
  383.     register int   i;
  384.     register char  *s;
  385.  
  386.     for( i = 0, s = "0ux1lUXhHUXL"; s[i] != '\0'; i++ )
  387.     if( s[i] == ch )
  388.         return( i & (N_POTS - 1) );
  389.  
  390.     error( filename, lineno, "%c: unknown node value\n", ch );
  391.     return( N_POTS );
  392.   }
  393.  
  394.  
  395. /*
  396.  * Open an input stream, and process commands from it.
  397.  * Returns 0 if file could not be opened, 1 otherwise.
  398.  */
  399. private int finput( name )
  400.   char  *name;
  401.   {
  402.     FILE  *fp = NULL;
  403.     int   olineno;
  404.     char  *ofname;
  405.     char  pathname[256];
  406.  
  407.     if( *name == '/' )                /* absolute path */
  408.     fp = fopen( name, "r" );
  409.     else
  410.       {
  411.     Path  *p;
  412.     for( p = cmdpath; p != NULL; p = p->next )
  413.       {
  414.         (void) sprintf( pathname, "%s/%s", p->name, name );
  415.         if( (fp = fopen( pathname, "r" )) != NULL )
  416.         break;
  417.       }
  418.       }
  419.     if( fp == NULL )
  420.     return( 0 );
  421.  
  422.     (void) strcpy( pathname, name );
  423.     ofname = filename;
  424.     olineno = lineno;
  425.     filename = pathname;
  426.     lineno = 0;
  427.     (void) input( fp );
  428.     (void) fclose( fp );
  429.     filename = ofname;
  430.     lineno = olineno;
  431.     return( 1 );
  432.   }
  433.  
  434.  
  435. #define    HashCmd( NM )    ( ((NM)[0] + (((NM)[1]) << 1) ) & (CMDTBLSIZE - 1) )
  436.  
  437. /*
  438.  * Execute a builtin command or read commands from a '.cmd' file.
  439.  */
  440. private int exec_cmd()
  441.   {
  442.     static char       missing_args[] = "missing arguments to \"%s\"\n";
  443.     static char       many_args[] = "too many arguments for \"%s\"\n";
  444.     register Command  *cmd;
  445.     char              *arg = targv[0];
  446.  
  447.     /* search command table, dispatch to handler, if any */
  448.     for( cmd = cmdtbl[ HashCmd( arg ) ]; cmd != NULL; cmd = cmd->next )
  449.       {
  450.  
  451. /*        lprintf( stdout, " arg = %s  \n",arg ); */
  452.  
  453.     if( strcmp( arg, cmd->name ) == 0 )
  454.       {
  455.         if( targc < cmd->nmin )
  456.         error( filename, lineno, missing_args, cmd->name );
  457.         else if( targc > cmd->nmax )
  458.         error( filename, lineno, many_args, cmd->name );
  459.         else
  460.         return( (*cmd->handler)() );
  461.         return( 0 );
  462.       }
  463.       }
  464.  
  465.     /* no built-in command found, try for a command file */
  466.     if( targc == 1 )
  467.       {
  468.     (void) strcat( arg, ".cmd" );
  469.     if( finput( arg ) )
  470.         return( 0 );
  471.     arg[ strlen( arg ) - 4 ] = '\0';
  472.       }
  473.  
  474.     error( filename, lineno, "unrecognized command: %s\n", arg );
  475.  
  476.     return( 0 );
  477.   }
  478.  
  479.  
  480. /* 
  481.  * Read and execute commands read from input stream.
  482.  */
  483. private int input( in )
  484.   FILE  *in;
  485.   {
  486.     static char  line[ LSIZE ];        /* static: use only 1 line buffer */
  487.     int          ret;
  488.  
  489.     while( 1 )
  490.       {
  491.       /* output prompt and flush output */
  492.     if( in == stdin )
  493.         (void) fputs( "irsim> ", stdout );
  494.     (void) fflush( stdout );
  495.  
  496.         /* read command */
  497.     if( fgetline( line, LSIZE, in ) == NULL )
  498.       {
  499.         if( (in != stdin) or not isatty( (int) fileno( stdin ) ) or
  500.           freopen( "/dev/tty", "r", stdin ) == NULL )
  501.         return( -1 );
  502.         (void) fputc( '\n', stdout );
  503.         continue;
  504.       }
  505.  
  506.     if( in == stdin )
  507.       {
  508.         if( logfile != NULL )
  509.         (void) fputs( line, logfile );
  510.       }
  511.     else if( dcmdfile )
  512.         (void) fprintf( stdout, "%s> %s", filename, line );
  513.  
  514.         /* convert line into tokens */
  515.     lineno += 1;
  516.     parse_line( line, LSIZE );
  517.     if( targc != 0 and (ret = exec_cmd()) != 0 )
  518.         return( ret );
  519.  
  520.         /* if user typed ^C stop reading and return to top level */
  521.     if( int_received )
  522.       {
  523.         if( in == stdin )
  524.         int_received = 0;
  525.         else
  526.           {
  527.         (void) fprintf( stderr, "interrupt <%s @ %d>...",
  528.           filename, lineno );
  529.         return( 1 );
  530.           }
  531.         (void) fputc( '\n', stderr );
  532.       }
  533.       }
  534.   }
  535.  
  536.  
  537. #define    CHECK_STOP() \
  538.   if( stoped_state ) \
  539.     { \
  540.     error( filename, lineno, not_in_stop ); \
  541.     return( 0 ); \
  542.    }
  543.  
  544. #define    UnAlias( N )    while( (N)->nflags & ALIAS ) (N) = (N)->nlink
  545.  
  546.  
  547. /*
  548.  * Read and process a command file (@ command).
  549.  */
  550. private int cmdfile()
  551.   {
  552.     if( not finput( targv[1] ) )
  553.     error( filename, lineno, "cannot open %s for input\n", targv[1] );
  554.  
  555.     return( 0 );
  556.   }
  557.  
  558.  
  559. /*
  560.  * Set or Print the search path for command files.
  561.  */
  562. private int docmdpath()
  563.   {
  564.     Path  *p, **last;
  565.     int   i;
  566.  
  567.     if( targc == 1 )
  568.       {
  569.         /* echo current cmdpath */
  570.     for( p = cmdpath; p != NULL; p = p->next )
  571.         lprintf( stdout, "%s ", p->name );
  572.     lprintf( stdout, "\n" );
  573.       }
  574.     else
  575.       {
  576.     if( strcmp( targv[1], "+" ) == 0 )
  577.         shift_args( TRUE );
  578.     else
  579.       {
  580.         while( (p = cmdpath) != NULL )
  581.           {
  582.         cmdpath = cmdpath->next;
  583.         Vfree( p );
  584.           }
  585.       }
  586.     last = &cmdpath;
  587.     for( i = 1; i < targc; i++ )
  588.       {
  589.         p = (Path *) Valloc( SIZEOF( Path ) + strlen( targv[i] ), 1 );
  590.         (void) strcpy( p->name, targv[i] );
  591.         p->next = NULL;
  592.         *last = p;
  593.         last = &p->next;
  594.       }
  595.       }
  596.     return( 0 );
  597.   }
  598.  
  599.  
  600. /*
  601.  * Initialize the path to be the current working directory.
  602.  */
  603. private void InitCmdPath()
  604.   {
  605.     targc = 2;
  606.     targv[1] = ".";
  607.     (void) docmdpath();
  608.   }
  609.  
  610.  
  611. /*
  612.  * Set value of a node/vector to the requested value (hlux).
  613.  */
  614. private int setvalue()
  615.   {
  616.     apply( setin, NULL, targv[0] );
  617.     return( 0 );
  618.   }
  619.  
  620.  
  621. /*
  622.  * add/delete node to/from display list.
  623.  */
  624. private int xwatch( n, flag )
  625.   nptr  n;
  626.   char  *flag;
  627.   {
  628.     UnAlias( n );
  629.  
  630.     if( not (n->nflags & MERGED) )
  631.       {
  632.     if( *flag == '+' )
  633.         iinsert_once( n, &wlist );
  634.     else
  635.         idelete( n, &wlist );
  636.       }
  637.     return( 1 );
  638.   }
  639.  
  640.  
  641. /*
  642.  * add/delete vector to/from display list
  643.  */
  644. private int vwatch( b, flag )
  645.   bptr  b;
  646.   char  *flag;
  647.   {
  648.     if( *flag == '+' )
  649.     iinsert_once( (nptr) b, &wvlist );
  650.     else
  651.     idelete( (nptr) b, &wvlist );
  652.  
  653.     return( 1 );
  654.   }
  655.  
  656.  
  657. /* manipulate display list */
  658. private int display()
  659.   {
  660.     apply( xwatch, vwatch, plus_minus );
  661.     return( 0 );
  662.   }
  663.  
  664.  
  665. /* display bit vector. */
  666. private int dvec( b )
  667.   register bptr  b;
  668.   {
  669.     register int  i;
  670.     char          bits[250];
  671.  
  672.     i = strlen( b->name ) + 2 + b->nbits;
  673.     if( column + i >= MAXCOL )
  674.       {
  675.     lprintf( stdout, "\n" );
  676.     column = 0;
  677.       }
  678.     column += i;
  679.     for( i = 0; i < b->nbits; i++ )
  680.     bits[i] = vchars[ b->nodes[i]->npot ];
  681.     bits[i] = '\0';
  682.  
  683.     lprintf( stdout, "%s=%s ", b->name, bits );
  684.  
  685.     return( 1 );
  686.   }
  687.  
  688.  
  689. /* 
  690.  * print value of specific node
  691.  */
  692. private void dnode( n )
  693.   register nptr  n;
  694.   {
  695.     register char  *name;
  696.     register int   i;
  697.  
  698.     name = pnode( n );
  699.     UnAlias( n );
  700.     i = strlen( name ) + ((n->nflags & MERGED) ? 23 : 3);
  701.     if( column + i >= MAXCOL )
  702.       {
  703.     lprintf( stdout, "\n" );
  704.     column = 0;
  705.       }
  706.     column += i;
  707.  
  708.     if( n->nflags & MERGED )
  709.     lprintf( stdout, "%s=<in transistor stack> ", name );
  710.     else
  711.     lprintf( stdout, "%s=%c ", name, vchars[ n->npot ] );
  712.   }
  713.  
  714.  
  715. /*
  716.  * print current simulated time and the state of the event list.
  717.  */
  718. private void prtime( col )
  719.   int  col;
  720.   {
  721.     if( col != 0 )
  722.     lprintf( stdout, "\n" );
  723.     lprintf( stdout, "time = %.1fns", d2ns( cur_delta ) );
  724.     if( npending )
  725.     lprintf( stdout, "; there are pending events (%d)",npending );
  726.     lprintf( stdout, "\n" );
  727.   }
  728.  
  729.  
  730. /*
  731.  * display node/vector values in display list
  732.  */
  733. private void pnwatchlist()
  734.   {
  735.     register iptr  w;
  736.  
  737.     column = 0;
  738.         /* print value of each watched bit vector. */
  739.     for( w = wvlist; w != NULL; w = w->next )
  740.     (void) dvec( (bptr) w->inode );
  741.  
  742.         /* now print value of each watched node. */
  743.     for( w = wlist; w != NULL; w = w->next )
  744.     dnode( (nptr) w->inode );
  745.  
  746.     prtime( column );
  747.   }
  748.  
  749.  
  750. /*
  751.  * Just append node to the list whose tail is pointed to by 'ptail'.
  752.  */
  753. private int get_nd_list( n, ptail )
  754.   nptr  n, **ptail;
  755.   {
  756.     if( not (n->nflags & VISITED) )
  757.       {
  758.     n->nflags |= VISITED;
  759.     n->n.next = NULL;
  760.     **ptail = n;
  761.     *ptail = &n->n.next;
  762.       }
  763.     return( 1 );
  764.   }
  765.  
  766.  
  767. /*
  768.  * display node values, either those specified or from display list
  769.  */
  770. private int pnlist()
  771.   {
  772.     if( targc == 1 )
  773.     pnwatchlist();
  774.     else
  775.       {
  776.     nptr  n = NULL, *ntail = &n;
  777.  
  778.     column = 0;
  779.  
  780.         /* first print any bit vectors the user has specified */
  781.     apply( get_nd_list, dvec, (char *) &ntail );
  782.  
  783.         /* then print individual nodes collected in the list */
  784.     for( ; n != NULL; n->nflags &= ~VISITED, n = n->n.next )
  785.         dnode( n );
  786.  
  787.     prtime( column );
  788.       }
  789.     return( 0 );
  790.   }
  791.  
  792.  
  793. /*
  794.  * set/clear trace bit in node
  795.  */
  796. private int xtrace( n, flag )
  797.   nptr  n;
  798.   char  *flag;
  799.   {
  800.     UnAlias( n );
  801.  
  802.     if( n->nflags & MERGED )
  803.       {
  804.     lprintf( stdout, "can't trace %s\n", pnode( n ) );
  805.     return( 1 );
  806.       }
  807.  
  808.     if( *flag == '+' )
  809.     n->nflags |= WATCHED;
  810.     else if( n->nflags & WATCHED )
  811.       {
  812.     lprintf( stdout, "%s was watched; not any more\n", pnode( n ) );
  813.     n->nflags &= ~WATCHED;
  814.       }
  815.  
  816.     return( 1 );
  817.   }
  818.  
  819. /*
  820.  * set/clear captrace bit in node
  821.  */
  822. private int xcaptrace( n, flag )
  823.   nptr  n;
  824.   char  *flag;
  825.   {
  826.     UnAlias( n );
  827.  
  828.     if( n->nflags & MERGED )
  829.       {
  830.     lprintf( stdout, "can't trace %s\n", pnode( n ) );
  831.     return( 1 );
  832.       }
  833.  
  834.     if( *flag == '+' )
  835.     n->nflags |= CAPWATCHED;
  836.     else if( n->nflags & CAPWATCHED )
  837.       {
  838.     lprintf( stdout, "%s was capwatched; not any more\n", pnode( n ) );
  839.     n->nflags &= ~CAPWATCHED;
  840.       }
  841.  
  842.     return( 1 );
  843.   }
  844.  
  845.  
  846. /*
  847.  * set/clear trace bit in vector
  848.  */
  849. private int vtrace( b, flag )
  850.   register bptr  b;
  851.   char           *flag;
  852.   {
  853.     register int   i;
  854.  
  855.     if( *flag == '+' )
  856.     b->traced |= WATCHVECTOR;
  857.     else
  858.       {
  859.     for( i = 0; i < b->nbits; i += 1 )
  860.         b->nodes[i]->nflags &= ~WATCHVECTOR;
  861.     b->traced &= ~WATCHVECTOR;
  862.       }
  863.     return( 1 );
  864.   }
  865.  
  866. /*
  867.  * set/clear captrace bit in vector
  868.  */
  869. private int vcaptrace( b, flag )
  870.   register bptr  b;
  871.   char           *flag;
  872.   {
  873.     register int   i;
  874.  
  875.     if( *flag == '+' )
  876.     b->traced |= CAPWATCHVECTOR;
  877.     else
  878.       {
  879.     for( i = 0; i < b->nbits; i += 1 )
  880.         b->nodes[i]->nflags &= ~CAPWATCHVECTOR;
  881.     b->traced &= ~CAPWATCHVECTOR;
  882.       }
  883.     return( 1 );
  884.   }
  885.  
  886.  
  887. /*
  888.  * just in case node appears in more than one bit vector, run through all
  889.  * the vectors being traced and make sure the flag is set for each node.
  890.  */
  891. private void set_vec_nodes( flag )
  892.   int  flag;
  893.   {
  894.     register bptr  b;
  895.     register int   i;
  896.  
  897.     for( b = blist; b != NULL; b = b->next )
  898.     if( b->traced & flag )
  899.         for( i = 0; i < b->nbits; i += 1 )
  900.         b->nodes[i]->nflags |= flag;
  901.   }
  902.  
  903.  
  904. /*
  905.  * set/clear stop bit in node
  906.  */
  907. private int nstop( n, flag )
  908.   nptr  n;
  909.   char  *flag;
  910.   {
  911.     UnAlias( n );
  912.  
  913.     if( n->nflags & MERGED )
  914.     return( 1 );
  915.  
  916.     if( *flag == '-' )
  917.     n->nflags &= ~STOPONCHANGE;
  918.     else
  919.     n->nflags |= STOPONCHANGE;
  920.  
  921.     return( 1 );
  922.   }
  923.  
  924.  
  925. /*
  926.  * set/clear stop bit in vector
  927.  */
  928. private int vstop( b, flag )
  929.   register bptr  b;
  930.   char           *flag;
  931.   {
  932.     register int   i;
  933.  
  934.     if( *flag == '+' )
  935.     b->traced |= STOPVECCHANGE;
  936.     else
  937.       {
  938.     for( i = 0; i < b->nbits; i += 1 )
  939.         b->nodes[i]->nflags &= ~STOPVECCHANGE;
  940.     b->traced &= ~STOPVECCHANGE;
  941.       }
  942.     return( 1 );
  943.   }
  944.  
  945.  
  946. /*
  947.  * mark nodes and vectors for tracing
  948.  */
  949. private int settrace()
  950.   {
  951.     apply( xtrace, vtrace, plus_minus );
  952.     set_vec_nodes( WATCHVECTOR );
  953.     return( 0 );
  954.   }
  955.  
  956.  
  957. /*
  958.  * Set flag that determines whether transitions on primary inputs will
  959.  * contribute to overall transition count used to determine total
  960.  * capacitance charged.  (PEL 5/4/93)
  961.  */
  962. private int setinputcap()
  963.   {
  964.     if( targc == 1 )
  965.       {
  966.     lprintf( stdout, "input capacitance transition accumulator is %s\n",
  967.       (count_InTrans) ? "ON" : "OFF" );
  968.     return( 0 );
  969.       }
  970.  
  971.     if( str_eql( "on", targv[1] ) == 0 )
  972.     count_InTrans = TRUE;
  973.     else if( str_eql( "off", targv[1] ) == 0 )
  974.     count_InTrans = FALSE;
  975.     else
  976.     error( filename, lineno, "don't know what '%s' means\n", targv[1] );
  977.  
  978.     return( 0 );
  979.   }
  980.  
  981.  
  982. /*
  983.  * mark nodes and vectors for cap tracing
  984.  */
  985. private int setcaptrace()
  986.   {
  987.     apply( xcaptrace, vcaptrace, plus_minus );
  988.     set_vec_nodes( CAPWATCHVECTOR );
  989.     return( 0 );
  990.   }
  991.  
  992.  
  993. /*
  994.  * Helper routine for summing capacitance
  995.  */
  996. private int sumcapdoit( n, capsum)
  997.   register nptr  n;
  998.   float *capsum;
  999.   {
  1000.     /* Don't UnAlias() before checking if it's an ALIAS node (PEL 5/31/93) */
  1001.     /* UnAlias( n ); */
  1002.  
  1003.     if( not (n->nflags & (MERGED | ALIAS)) )
  1004.     *capsum += n->ncap;
  1005.  
  1006.     if( VDD_node != NULL and str_eql( pnode( n ) , pnode( VDD_node ) ) == 0 )
  1007.     VddCap += n->ncap;
  1008.  
  1009.     if( GND_node != NULL and str_eql( pnode( n ) , pnode( GND_node ) ) == 0 )
  1010.     GndCap += n->ncap;
  1011.  
  1012.     return( 0 );
  1013.   }
  1014.  
  1015. /*
  1016.  * Print sum of capacitance of nodes
  1017.  */
  1018. private int sumcap()
  1019.   {
  1020.     float capsum = 0;
  1021.  
  1022.     GndCap = VddCap = 0;
  1023.     walk_net( sumcapdoit, (char *) &capsum ) ;
  1024.     lprintf( stdout, " Sum of nodal capacitances (excluding Gnd and Vdd): %f pF\n",
  1025.         capsum - VddCap - GndCap );
  1026.     lprintf( stdout, " Vdd capacitance: %f pF \n",VddCap );
  1027.  
  1028.     return( 0 );
  1029.   }
  1030.  
  1031.  
  1032. /*
  1033.  * Set the supply voltage to a known value -- used in calculating power
  1034.  */
  1035. private int setvsupply()
  1036.   {
  1037.     if( targc == 2 )
  1038.     vsupply = atof( targv[1] );
  1039.     lprintf( stdout, "Supply Voltage = %4.2f Volts\n", vsupply );
  1040.     return(0);
  1041.   }
  1042.  
  1043.  
  1044. /*
  1045.  * Helper routine for zeroing transition counts (PEL 4/30/93). 
  1046.  * Zeros even MERGE and ALIAS node transition counts since this can't
  1047.  * hurt anything.
  1048.  */
  1049. private int zeropowerdoit( n )
  1050.   register nptr  n;
  1051.   {
  1052.     n->trans = 0;
  1053.     n->trans01 = 0.0;    /* PEL 5/3/93 */
  1054.  
  1055.     return( 0 );
  1056.   }
  1057.  
  1058.  
  1059. /*
  1060.  * Zero totpower and transition counts for all nodes (PEL 4/30/93)
  1061.  */
  1062. private int zeropower()
  1063.   {
  1064.     walk_net( zeropowerdoit, (char *) 0 );
  1065.     totpower = 0;
  1066.     capstarttime = d2ns(cur_delta); /*MOD 95 */
  1067.     return( 0 );
  1068.   }
  1069.  
  1070.  
  1071. /*
  1072.  * mark nodes and vectors for stoping
  1073.  */
  1074. private int setstop()
  1075.   {
  1076.     if( isatty( (int) fileno( stdin ) ) )
  1077.       {
  1078.     apply( nstop, vstop, plus_minus );
  1079.     set_vec_nodes( STOPVECCHANGE );
  1080.       }
  1081.     return( 0 );
  1082.   }
  1083.  
  1084.  
  1085. /*
  1086.  * define bit vector
  1087.  */
  1088. private int dovector()
  1089.   {
  1090.     register nptr  n;
  1091.     register bptr  b, last;
  1092.     register int   i;
  1093.  
  1094.     if( find( targv[1] ) != NULL )
  1095.       {
  1096.     error( filename, lineno, "'%s' is a node, can't be a vector\n",
  1097.       targv[1] );
  1098.     return( 0 );
  1099.       }
  1100.  
  1101.     /* get rid of any vector with the same name */
  1102.     for( b = blist, last = NULL; b != NULL; last = b, b = b->next )
  1103.     if( strcmp( b->name, targv[1] ) == 0 )
  1104.       {
  1105.         if( undefseq( (nptr) b, &slist, &maxsequence ) or
  1106.           undefseq( (nptr) b, &clock, &maxclock ) )
  1107.           {
  1108.         error( filename, lineno,
  1109.           "%s is a clock/sequence; can't change it while stoped\n",
  1110.           b->name );
  1111.         return( 0 );
  1112.           }
  1113.         idelete( (nptr) b, &wvlist );    /* untrace its nodes */
  1114.         if( last == NULL )
  1115.         blist = b->next;
  1116.         else
  1117.         last->next = b->next;        /* remove from display list */
  1118.         (void) vtrace( b, "-" );
  1119.         if( analyzerON )
  1120.         RemoveVector( b );
  1121.         Vfree( b->name );
  1122.         Vfree( b );
  1123.         break;
  1124.       }
  1125.     b = (bptr) Valloc( SIZEOF( Bits ) + (targc - 3) * SIZEOF( nptr ), 0 );
  1126.     if( b == NULL or (b->name = Valloc( strlen( targv[1] ) + 1, 0 )) == NULL )
  1127.       {
  1128.     if( b ) Vfree( b );
  1129.     error( filename, lineno, "Not enough memory for vector\n" );
  1130.     return( 0 );
  1131.       }
  1132.     b->traced = 0;
  1133.     b->nbits = 0;
  1134.     (void) strcpy( b->name, targv[1] );
  1135.  
  1136.     for( i = 2; i < targc; i += 1 )
  1137.       {
  1138.     if( (n = find( targv[i] )) == NULL )
  1139.         error( filename, lineno, "cannot find node %s\n", targv[i] );
  1140.     else
  1141.       {
  1142.         UnAlias( n );
  1143.         if( n->nflags & MERGED )
  1144.         error( filename, lineno, "%s can not be part of a vector\n",
  1145.           pnode( n ) );
  1146.         else
  1147.         b->nodes[b->nbits++] = n;
  1148.       }
  1149.       }
  1150.  
  1151.     if( b->nbits == targc - 2 )
  1152.       {
  1153.     b->next = blist;
  1154.     blist = b;
  1155.       }
  1156.     else
  1157.       {
  1158.     Vfree( b->name );
  1159.     Vfree( b );
  1160.       }
  1161.  
  1162.     return( 0 );
  1163.   }
  1164.  
  1165.  
  1166. /* set bit vector */
  1167. private int setvector()
  1168.   {
  1169.     register bptr  b;
  1170.     register int   i;
  1171.     char           *val = targv[2];
  1172.  
  1173.     /* find vector */
  1174.     for( b = blist; b != NULL; b = b->next )
  1175.       {
  1176.     if( str_eql( b->name, targv[1] ) == 0 )
  1177.         goto got_it;
  1178.       }
  1179.  
  1180.     error( filename, lineno, "%s: No such vector\n", targv[1] );
  1181.     return( 0 );
  1182.  
  1183.   got_it :
  1184.     /* set nodes */
  1185.     if( strlen( targv[2] ) != b->nbits )
  1186.       {
  1187.     error( filename, lineno, "wrong number of bits for this vector\n" );
  1188.     return( 0 );
  1189.       }
  1190.     for( i = 0; i < b->nbits; i++ )
  1191.       {
  1192.     if( (val[i] = potchars[ ch2pot( val[i] ) ]) == '.' )
  1193.         return( 0 );
  1194.       }
  1195.     for( i = 0; i < b->nbits; i++ )
  1196.     (void) setin( b->nodes[i], val++ );
  1197.  
  1198.     return( 0 );
  1199.   }
  1200.  
  1201.  
  1202. private void CompareVector( np, name, nbits, mask, value )
  1203.   nptr  *np;
  1204.   char  *name;
  1205.   int   nbits;
  1206.   char  *mask;
  1207.   char  *value;
  1208.   {
  1209.     int   i, val;
  1210.     nptr  n;
  1211.  
  1212.     if( strlen( value ) != nbits )
  1213.       {
  1214.     error( filename, lineno, "wrong number of bits for value\n" );
  1215.     return;
  1216.       }
  1217.     if( mask != NULL and strlen( mask ) != nbits )
  1218.       {
  1219.     error( filename, lineno, "wrong number of bits for mask\n" );
  1220.     return;
  1221.       }
  1222.  
  1223.     for( i = 0; i < nbits; i++ )
  1224.       {
  1225.     if( mask != NULL and mask[i] != '0' )
  1226.         continue;
  1227.     n = np[i];
  1228.     if( (val = ch2pot( value[i] )) >= N_POTS )
  1229.         return;
  1230.  
  1231.     if( n->npot != (val == X_X) ? X : val )
  1232.         goto fail;
  1233.       }
  1234.     return;
  1235.  
  1236.   fail :
  1237.     lprintf( stdout, "(%s, %d): assertion failed on '%s' ",
  1238.      filename, lineno, name );
  1239.     for( i = 0; i < nbits; i++ )
  1240.       {
  1241.     if( mask != NULL and mask[i] != '0' )
  1242.       {
  1243.         lprintf( stdout, "-" );
  1244.         value[i] = '-';
  1245.       }
  1246.     else
  1247.         lprintf( stdout, "%c", vchars[ np[i]->npot ] );
  1248.       }
  1249.     lprintf( stdout, " (%s)\n", value );
  1250.   }
  1251.  
  1252.  
  1253. typedef struct
  1254.   {
  1255.     nptr  node;
  1256.     bptr  vec;
  1257.     int   num;
  1258.   } Find1Arg;
  1259.  
  1260.  
  1261. private int SetNode( nd, find_one )
  1262.   nptr      nd;
  1263.   Find1Arg  *find_one;
  1264.   {
  1265.     find_one->node = nd;
  1266.     find_one->num++;
  1267.     return( 1 );
  1268.   }
  1269.  
  1270. private int SetVector( bp, find_one )
  1271.   bptr      bp;
  1272.   Find1Arg  *find_one;
  1273.   {
  1274.     find_one->vec = bp;
  1275.     find_one->num++;
  1276.     return( 1 );
  1277.   }
  1278.  
  1279.  
  1280. /* find vector or node (1st argument) */
  1281. private void FindOne( f )
  1282.   Find1Arg  *f;
  1283.   {
  1284.     targc = 2;
  1285.     f->num = 0;
  1286.     f->vec = NULL;
  1287.     f->node = NULL;
  1288.     apply( SetNode, SetVector, (char *) f );
  1289.   }
  1290.   
  1291.  
  1292. /* assert a bit vector */
  1293. private int doAssert()
  1294.   {
  1295.     char      *mask, *value, *name;
  1296.     Find1Arg  f;
  1297.  
  1298.     if( targc == 4 )
  1299.       {
  1300.     mask = targv[2];
  1301.     value = targv[3];
  1302.       }
  1303.     else
  1304.       {
  1305.     mask = NULL;
  1306.     value = targv[2];
  1307.       }
  1308.  
  1309.     FindOne( &f );
  1310.  
  1311.     if( f.num > 1 )
  1312.     error( filename, lineno, "%s matches more than one node or vector\n",
  1313.       targv[1] );
  1314.     else if( f.node != NULL )
  1315.       {
  1316.     name = pnode( f.node );
  1317.     UnAlias( f.node );
  1318.     CompareVector( &f.node, name, 1, mask, value );
  1319.       }
  1320.     else if( f.vec != NULL )
  1321.     CompareVector( f.vec->nodes, f.vec->name, f.vec->nbits, mask, value );
  1322.  
  1323.     return( 0 );
  1324.   }
  1325.  
  1326.  
  1327. private int collect_inputs( n, inps )
  1328.   register nptr  n;
  1329.   register nptr  inps[];
  1330.   {
  1331.     if( (n->nflags & (INPUT|ALIAS|POWER_RAIL|VISITED|INPUT_MASK) ) == INPUT )
  1332.       {
  1333.     n->n.next = inps[ n->npot ];
  1334.     inps[ n->npot ] = n;
  1335.     n->nflags |= VISITED;
  1336.       }
  1337.     return( 0 );
  1338.   }
  1339.  
  1340.  
  1341. /* display current inputs */
  1342. private int inputs()
  1343.   {
  1344.     register iptr  list;
  1345.     register nptr  n;
  1346.     nptr           inptbl[ N_POTS ];
  1347.  
  1348.     inptbl[ HIGH ] = inptbl[ LOW ] = inptbl[ X ] = NULL;
  1349.     walk_net( collect_inputs, (char *) inptbl );
  1350.  
  1351.     lprintf( stdout, "h inputs: " );
  1352.     for( list = hinputs; list != NULL; list = list->next )
  1353.     lprintf( stdout, "%s ", pnode( list->inode ) );
  1354.     for( n = inptbl[ HIGH ]; n != NULL; n->nflags &= ~VISITED, n = n->n.next )
  1355.     lprintf( stdout, "%s ", pnode( n ) );
  1356.     lprintf( stdout, "\nl inputs: " );
  1357.     for( list = linputs; list != NULL; list = list->next )
  1358.     lprintf( stdout, "%s ", pnode( list->inode ) );
  1359.     for( n = inptbl[ LOW ]; n != NULL; n->nflags &= ~VISITED, n = n->n.next )
  1360.     lprintf( stdout, "%s ", pnode( n ) );
  1361.     lprintf( stdout, "\nu inputs: " );
  1362.     for( list = uinputs; list != NULL; list = list->next )
  1363.     lprintf( stdout, "%s ", pnode( list->inode ) );
  1364.     for( n = inptbl[ X ]; n != NULL; n->nflags &= ~VISITED, n = n->n.next )
  1365.     lprintf( stdout, "%s ", pnode( n ) );
  1366.     lprintf( stdout, "\n" );
  1367.     return( 0 );
  1368.   }
  1369.  
  1370.  
  1371. /* set stepsize */
  1372. private int setstep()
  1373.   {
  1374.     if( targc == 1 )
  1375.     lprintf( stdout, "stepsize = %f\n", d2ns( stepsize ) );
  1376.     else if( targc == 2 )
  1377.       {
  1378.     long  newsize = (long) ns2d( atof( targv[1] ) );
  1379.  
  1380.     if( newsize <= 0 )
  1381.         error( filename, lineno, "bad step size: %s\n", targv[1] );
  1382.     else
  1383.         stepsize = newsize;
  1384.       }
  1385.     return( 0 );
  1386.   }
  1387.  
  1388.  
  1389. /*
  1390.  * Display traced vectors that just changed.  There should be at least one.
  1391.  */
  1392. public void disp_watch_vec( which )
  1393.   long  which;
  1394.   {
  1395.     register bptr  b;
  1396.     register int   i;
  1397.     char           temp[20];
  1398.  
  1399.     which &= (WATCHVECTOR | STOPVECCHANGE);
  1400.     (void) sprintf( temp, " @ %.1fns ", d2ns( cur_delta ) );
  1401.     lprintf( stdout, "%s", temp );
  1402.     column = strlen( temp );
  1403.     for( b = blist; b != NULL; b = b->next )
  1404.       {
  1405.     if( (b->traced & which) == 0 )
  1406.         continue;
  1407.     for( i = b->nbits - 1; i >= 0; i-- )
  1408.         if( b->nodes[i]->c.time == cur_delta )
  1409.         break;
  1410.     if( i >= 0 )
  1411.         (void) dvec( b );
  1412.       }
  1413.     lprintf( stdout, "\n" );
  1414.   }
  1415.  
  1416.  
  1417. private void EnterStopState()
  1418.   {
  1419.     char  *ofname = filename;
  1420.     int   olineno = lineno;
  1421.  
  1422.     lprintf( stdout, "--> STOP  " );
  1423.     prtime( 0 );
  1424.     filename = "STOP";
  1425.     lineno = 0;
  1426.     stoped_state = TRUE;
  1427.     while( input( stdin ) <= 0 );    /* ignore quit */
  1428.     stoped_state = FALSE;
  1429.     lineno = olineno;
  1430.     filename = ofname;
  1431.   }
  1432.  
  1433.  
  1434. /* 
  1435.  * Settle network until the specified stop time is reached.
  1436.  * Premature returns (before stop time) indicate that a node/vector whose
  1437.  * stop-bit set has just changed value, so popup a stdin command interpreter.
  1438.  */
  1439. private int relax( stoptime )
  1440.   long  stoptime;
  1441.   {
  1442.     while( step( stoptime ) )
  1443.       {
  1444.     EnterStopState();
  1445.       }
  1446.     return( cur_delta - stoptime );
  1447.   }
  1448.  
  1449.  
  1450. /*
  1451.  * relax network, optionally set stepsize
  1452.  */
  1453. private int dostep()
  1454.   {
  1455.     long newsize;
  1456.  
  1457.     CHECK_STOP();
  1458.  
  1459.     if( targc == 2 )
  1460.       {
  1461.     newsize = (long) ns2d( atof( targv[1] ) );
  1462.     if( newsize <= 0 )
  1463.       {
  1464.         error( filename, lineno, "bad step size: %s\n", targv[1] );
  1465.         return( 0 );
  1466.       }
  1467.       }
  1468.     else
  1469.     newsize = stepsize;
  1470.  
  1471.     (void) relax( cur_delta + newsize );
  1472.     if( ddisplay )
  1473.     pnwatchlist();
  1474.  
  1475.     return( 0 );
  1476.   }
  1477.  
  1478.  
  1479. /*
  1480.  * display info about a node
  1481.  */
  1482. private int quest()
  1483.   {
  1484.     apply( info, NULL, targv[0] );
  1485.     return( 0 );
  1486.   }
  1487.  
  1488.  
  1489. /*
  1490.  * exit this level of command processing
  1491.  */
  1492. private int quit()
  1493.   {
  1494.     return( -1 );
  1495.   }
  1496.  
  1497.  
  1498. /*
  1499.  * return to command level
  1500.  */
  1501. private int doexit()
  1502.   {
  1503.     TerminateAnalyzer();
  1504.  
  1505.     exit( (targc == 2) ? atoi( targv[1] ) : 0 );
  1506.   }
  1507.  
  1508.  
  1509. /*
  1510.  * destroy sequence for given node/vector: update sequence list and length.
  1511.  * return -1 if we can't destroy the sequence (in stopped state).
  1512.  */
  1513. private int undefseq( p, list, lmax )
  1514.   nptr  p;
  1515.   sptr  *list;
  1516.   int   *lmax;
  1517.   {
  1518.     register sptr  u, t;
  1519.     register int   i;
  1520.  
  1521.     for( u = NULL, t = *list; t != NULL; u = t, t = t->next )
  1522.     if( t->ptr.n == p )
  1523.         break;
  1524.     if( t )
  1525.       {
  1526.     if( stoped_state )    /* disallow changing sequences if stoped */
  1527.         return( -1 );
  1528.     if( u == NULL )
  1529.         *list = t->next;
  1530.     else
  1531.         u->next = t->next;
  1532.     Vfree( t );
  1533.     for( i = 0, t = *list; t != NULL; t = t->next )
  1534.         if( t->nvalues > i ) i = t->nvalues;
  1535.     *lmax = i;
  1536.       }
  1537.     return( 0 );
  1538.   }
  1539.  
  1540.  
  1541. /*
  1542.  * process command line to yield a sequence structure.  first arg is the
  1543.  * name of the node/vector for which the sequence is to be defined, second
  1544.  * and following args are the values.
  1545.  */
  1546. private void defsequence( list, lmax )
  1547.   sptr  *list;
  1548.   int   *lmax;
  1549.   {
  1550.     register sptr  s;
  1551.     register nptr  n;
  1552.     register bptr  b;
  1553.     register int   i;
  1554.     register char  *q;
  1555.     int            which, size;
  1556.  
  1557.     /* if no arguments, get rid of all the sequences we have defined */
  1558.     if( targc == 1 )
  1559.       {
  1560.     while( *list != NULL )
  1561.         (void) undefseq( (*list)->ptr.n, list, lmax );
  1562.     return;
  1563.       }
  1564.  
  1565.     /* see if we can determine if name is for node or vector */
  1566.     for( b = blist; b != NULL; b = b->next )
  1567.     if( str_eql( b->name, targv[1] ) == 0 )
  1568.       {
  1569.         which = 1;    size = b->nbits;    goto okay;
  1570.       }
  1571.  
  1572.     n = find( targv[1] );
  1573.     if( n == NULL )
  1574.       {
  1575.     error( filename, lineno, "%s: No such node or vector\n", targv[1] );
  1576.     return;
  1577.       }
  1578.     UnAlias( n );
  1579.     if( n->nflags & MERGED )
  1580.       {
  1581.     error(filename, lineno, "%s can't be part of a sequence\n", pnode(n));
  1582.     return;
  1583.       }
  1584.     which = 0; size = 1;
  1585.  
  1586.   okay :
  1587.     if( targc == 2 )    /* just destroy the given sequence */
  1588.       {
  1589.     (void) undefseq( which ? (nptr) b : n, list, lmax );
  1590.     return;
  1591.       }
  1592.  
  1593.     /* make sure each value specification is the right length */
  1594.     for( i = 2; i < targc; i += 1 )
  1595.     if( strlen( targv[ i ] ) != size )
  1596.       {
  1597.         error( filename, lineno,
  1598.           "value \"%s\" is not compatible with size of %s (%d)\n",
  1599.           targv[ i ], targv[2], size );
  1600.         return;
  1601.       }
  1602.  
  1603.     s = (sptr) Valloc( SIZEOF( sequence ) + size * (targc - 2) - 1, 0 );
  1604.     if( s == NULL )
  1605.       {
  1606.     error( filename, lineno, "Insufficient memory for sequence\n" );
  1607.     return;
  1608.       }
  1609.     s->which = which;
  1610.     s->vsize = size;
  1611.     s->nvalues = targc - 2;
  1612.     if( which )    s->ptr.b = b;
  1613.     else    s->ptr.n = n;
  1614.  
  1615.       /* process each value specification saving results in sequence */
  1616.     for( q = s->values, i = 2; i < targc; i += 1 )
  1617.       {
  1618.     register char  *p;
  1619.  
  1620.     for( p = targv[i]; *p != 0; p++ )
  1621.         if( (*q++ = potchars[ ch2pot( *p ) ]) == '.' )
  1622.           {
  1623.         Vfree( s );
  1624.         return;
  1625.           }
  1626.       }
  1627.  
  1628.     /* all done!  remove any old sequences for this node or vector. */
  1629.     (void) undefseq( s->ptr.n, list, lmax );
  1630.  
  1631.     /* insert result onto list */
  1632.     s->next = *list;
  1633.     *list = s;
  1634.     if( s->nvalues > *lmax )
  1635.     *lmax = s->nvalues;
  1636.   }
  1637.  
  1638.  
  1639. /*
  1640.  * mark any vector that contains a deleted node (used by netupdate).
  1641.  */
  1642. private int mark_deleted_vectors()
  1643.   {
  1644.     register bptr  b;
  1645.     register int   i, total = 0;
  1646.  
  1647.     for( b = blist; b != NULL; b = b->next )
  1648.       {
  1649.     for( i = b->nbits - 1; i >= 0; i-- )
  1650.       {
  1651.         if( b->nodes[i]->nflags & DELETED )
  1652.           {
  1653.         b->traced = DELETED;
  1654.         total ++;
  1655.         break;
  1656.           }
  1657.         UnAlias( b->nodes[i] );
  1658.       }
  1659.       }
  1660.     return( total );
  1661.   }
  1662.  
  1663.  
  1664. /*
  1665.  * Remove all deleted nodes/vectors from the sequence list
  1666.  */
  1667. private int rm_from_seq( list )
  1668.   register sptr  *list;
  1669.   {
  1670.     register sptr  s;
  1671.     register int   max;
  1672.  
  1673.     max = 0;
  1674.     while( (s = *list) != NULL )
  1675.       {
  1676.     if( ((s->which) ? s->ptr.b->traced : s->ptr.n->nflags) & DELETED )
  1677.       {
  1678.         *list = s->next;
  1679.         Vfree( s );
  1680.       }
  1681.     else
  1682.       {
  1683.         if( s->which == 0 )
  1684.         UnAlias( s->ptr.n );
  1685.  
  1686.         if( s->nvalues > max )
  1687.         max = s->nvalues;
  1688.         list = &(s->next);
  1689.       }
  1690.       }
  1691.     return( max );
  1692.   }
  1693.  
  1694.  
  1695. /*
  1696.  * Remove any deleted node/vector from any lists in which it may appear.
  1697.  */
  1698. public void rm_del_from_lists()
  1699.   {
  1700.     register iptr  w, *list;
  1701.     int            vec_del;
  1702.  
  1703.     vec_del = mark_deleted_vectors();
  1704.  
  1705.     maxsequence = rm_from_seq( &slist );
  1706.     maxclock = rm_from_seq( &clock );
  1707.  
  1708.     if( analyzerON ) RemoveAllDeleted();
  1709.  
  1710.     for( list = &wvlist; (w = *list) != NULL; )
  1711.       {
  1712.     if( ((bptr) (w->inode))->traced & DELETED )
  1713.       {
  1714.         *list = w->next;
  1715.         FreeInput( w );
  1716.       }
  1717.     else
  1718.         list = &w->next;
  1719.       }
  1720.  
  1721.     for( list = &wlist; (w = *list) != NULL; )
  1722.       {
  1723.     if( w->inode->nflags & DELETED )
  1724.       {
  1725.         *list = w->next;
  1726.         FreeInput( w );
  1727.       }
  1728.     else
  1729.       {
  1730.         UnAlias( w->inode );
  1731.         list = &w->next;
  1732.       }
  1733.       }
  1734.  
  1735.     if( vec_del )
  1736.       {
  1737.     register bptr  b, *lst;
  1738.  
  1739.     for( lst = &blist; (b = *lst) != NULL; )
  1740.       {
  1741.         if( b->traced & DELETED )
  1742.           {
  1743.         *lst = b->next;
  1744.         Vfree( b->name );
  1745.         Vfree( b );
  1746.           }
  1747.         else
  1748.         lst = &b->next;
  1749.       }
  1750.       }
  1751.   }
  1752.  
  1753.  
  1754. /*
  1755.  * set each node/vector in sequence list to its next value
  1756.  */
  1757. private void vecvalue( list, index )
  1758.   register sptr  list;
  1759.   int            index;
  1760.   {
  1761.     register int   offset, i;
  1762.     register nptr  *n;
  1763.  
  1764.     for( ; list != NULL; list = list->next )
  1765.       {
  1766.     offset = list->vsize * (index % list->nvalues);
  1767.     n = (list->which == 0) ? &list->ptr.n : list->ptr.b->nodes;
  1768.     for( i = 0; i < list->vsize; i++ )
  1769.         (void) setin( *n++, &list->values[ offset++ ] );
  1770.       }
  1771.   }
  1772.  
  1773.  
  1774. /*
  1775.  * setup sequence of values for a node
  1776.  */
  1777. private int setseq()
  1778.   {
  1779.     CHECK_STOP();
  1780.     /* process sequence and add to list */
  1781.     defsequence( &slist, &maxsequence );
  1782.     return( 0 );
  1783.   }
  1784.  
  1785.  
  1786. /*
  1787.  * define clock sequences(s)
  1788.  */
  1789. private int setclock()
  1790.   {
  1791.     CHECK_STOP();
  1792.     /* process sequence and add to clock list */
  1793.     defsequence( &clock, &maxclock );
  1794.     return( 0 );
  1795.   }
  1796.  
  1797.  
  1798. /*
  1799.  * Step each clock node through one simulation step
  1800.  */
  1801. private int step_phase()
  1802.   {
  1803.     static int  which_phase = 0;
  1804.  
  1805.     vecvalue( clock, which_phase );
  1806.     if( relax( cur_delta + stepsize ) )
  1807.     return( 1 );
  1808.     which_phase = (which_phase + 1) % maxclock;
  1809.     return( 0 );
  1810.   }
  1811.  
  1812.  
  1813. /* Do one simulation step */
  1814. private int dophase()
  1815.   {
  1816.     CHECK_STOP();
  1817.  
  1818.     (void) step_phase();
  1819.     if( ddisplay )
  1820.     pnwatchlist();
  1821.  
  1822.     return( 0 );
  1823.   }
  1824.  
  1825.  
  1826. /*
  1827.  * clock circuit specified number of times
  1828.  */
  1829. private int clockit( n )
  1830.   register int  n;
  1831.   {
  1832.     register int  i;
  1833.  
  1834.     if( clock == NULL )
  1835.     error( filename, lineno, "no clock nodes defined!\n" );
  1836.     else
  1837.       {
  1838.       /* run 'em by setting each clock node to successive values of its
  1839.        * associated sequence until all phases have been run.
  1840.        */
  1841.     while( n-- > 0 )
  1842.         for( i = 0; i < maxclock; i += 1 )
  1843.         if( step_phase() )
  1844.             goto done;
  1845.  
  1846.         /* finally display results if requested to do so */
  1847.       done :
  1848.     if( ddisplay )
  1849.         pnwatchlist();
  1850.       }
  1851.     return( maxclock - i );
  1852.   }
  1853.  
  1854.  
  1855. /*
  1856.  * clock circuit through all the input vectors previously set up
  1857.  */
  1858. private int runseq()
  1859.   {
  1860.     register int  i, n = 1;
  1861.  
  1862.     CHECK_STOP();
  1863.  
  1864.     /* calculate how many clock cycles to run */
  1865.     if( targc == 2 )
  1866.       {
  1867.     n = atoi( targv[1] );
  1868.     if( n <= 0 )
  1869.         n = 1;
  1870.       }
  1871.  
  1872.     /* run 'em by setting each input node to successive values of its
  1873.      * associated sequence.
  1874.      */
  1875.     if( slist == NULL )
  1876.     error( filename, lineno, "no input vectors defined!\n" );
  1877.     else
  1878.     while( n-- > 0 )
  1879.         for( i = 0; i < maxsequence; i += 1 )
  1880.           {
  1881.         vecvalue( slist, i );
  1882.         if( clockit( 1 ) )
  1883.             return( 0 );
  1884.         if( ddisplay )
  1885.             pnwatchlist();
  1886.           }
  1887.  
  1888.     return( 0 );
  1889.   }
  1890.  
  1891.  
  1892. /*
  1893.  * process "c" command line
  1894.  */
  1895. private int doclock()
  1896.   {
  1897.     register int  i, n = 1;
  1898.  
  1899.     if( stoped_state )        /* continue after stop */
  1900.     return( 1 );
  1901.  
  1902.     /* calculate how many clock cycles to run */
  1903.     if( targc == 2 )
  1904.       {
  1905.     n = atoi( targv[1] );
  1906.     if( n <= 0 )
  1907.         n = 1;
  1908.       }
  1909.  
  1910.     (void) clockit( n );        /* do the hard work */
  1911.     return( 0 );
  1912.   }
  1913.  
  1914.  
  1915. /*
  1916.  * output message to console/log file
  1917.  */
  1918. private int domsg()
  1919.   {
  1920.     int  n;
  1921.  
  1922.     for( n = 1; n < targc; n += 1 )
  1923.     lprintf( stdout, "%s ", targv[n] );
  1924.     lprintf( stdout, "\n" );
  1925.     return( 0 );
  1926.   }
  1927.  
  1928.  
  1929. /*
  1930.  * Return a number whose bits corresponding to the index of 'words' match
  1931.  * the argument.
  1932.  * If 'offwrd' is given then that argument turns all bits off.
  1933.  * If 'offwrd' is given and the argument is '*' turns all bits on.
  1934.  * if the argument is '?' the display the avaliable options (words).
  1935.  * With no arguments just prints the word whose corresponding bit is set.
  1936.  */
  1937. private int do_flags( bits, name, offwrd, words )
  1938.   int   bits;
  1939.   char  *name, *offwrd, *words[];
  1940.   {
  1941.     int  i, t, tmp;
  1942.  
  1943.     if( targc == 1 )
  1944.       {
  1945.     lprintf( stdout, "%s: ", name );
  1946.     if( bits == 0 and offwrd != NULL )
  1947.         lprintf( stdout, offwrd );
  1948.     else
  1949.       {
  1950.         for( i = 0; words[i] != NULL; i++ )
  1951.         if( bits & (1 << i) )
  1952.             lprintf( stdout, " %s", words[i] );
  1953.       }
  1954.     lprintf( stdout, "\n" );
  1955.       }
  1956.     else if( targc == 2 and strcmp( targv[1], "?" ) == 0 )
  1957.       {
  1958.     lprintf( stdout, "%s options are:", name );
  1959.     if( offwrd )
  1960.         lprintf( stdout, "[*][%s]", offwrd );
  1961.     for( t = '[', i = 0; words[i] != NULL; i++, t = ' ' )
  1962.         lprintf( stdout, "%c%s", t, words[i] );
  1963.     lprintf( stdout, "]\n" );
  1964.       }
  1965.     else if( targc == 2 and offwrd != 0 and strcmp( targv[1], offwrd ) == 0 )
  1966.       {
  1967.     bits = 0;
  1968.       }
  1969.     else if( targc == 2 and offwrd != 0 and str_eql( targv[1], "*" ) == 0 )
  1970.       {
  1971.     for( i = 0; words[i] != NULL; i++ );
  1972.     bits = (1 << i) - 1;
  1973.       }
  1974.     else
  1975.       {
  1976.     for( t = 1, tmp = bits, bits = 0; t < targc; t++ )
  1977.       {
  1978.         for( i = 0; words[i] != NULL; i++ )
  1979.         if( str_eql( words[i], targv[t] ) == 0 )
  1980.           {
  1981.             bits |= (1 << i);
  1982.             break;
  1983.           }
  1984.         if( words[i] == NULL )
  1985.           {
  1986.         error( filename, lineno, "%s: Invalid %s option\n",
  1987.          targv[t], name );
  1988.         bits = tmp;
  1989.         break;
  1990.           }
  1991.       }
  1992.       }
  1993.     return( bits );
  1994.   }
  1995.  
  1996.  
  1997.     /* various debug flags */
  1998. public
  1999. #define    DEBUG_EV        0x01        /* event scheduling */
  2000. public
  2001. #define    DEBUG_DC        0x02        /* final value computation */
  2002. public
  2003. #define    DEBUG_TAU        0x04        /* tau/delay computation */
  2004. public
  2005. #define    DEBUG_TAUP        0x08        /* taup computation */
  2006. public
  2007. #define    DEBUG_SPK        0x10        /* spike analysis */
  2008. public
  2009. #define    DEBUG_TW        0x20        /* tree walk */
  2010.  
  2011.  
  2012. /* set debugging level */
  2013. private int setdbg()
  2014.   {
  2015.     static char  *dbg[] = { "ev", "dc", "tau", "taup", "spk", "tw", NULL };
  2016.     int          new;
  2017.  
  2018.     new = do_flags( debug, "Debug", "off", dbg );
  2019.     if( new != debug )
  2020.       {
  2021.     debug = new;
  2022.     targc = 1;
  2023.     (void) do_flags( debug, "Debug is now", "OFF", dbg );
  2024.       }
  2025.     return( 0 );
  2026.   }
  2027.  
  2028.  
  2029. public
  2030. #define    REPORT_DECAY    0x1
  2031. public
  2032. #define    REPORT_DELAY    0x2
  2033. public
  2034. #define    REPORT_TAU    0x4
  2035. public
  2036. #define    REPORT_TCOORD    0x8
  2037. public
  2038. #define    REPORT_CAP    0x10
  2039.  
  2040.  
  2041. /*
  2042.  * set treport parameter
  2043.  */
  2044. private int setreport()
  2045.   {
  2046.     static char  *rep[] = { "decay", "delay", "tau", "tcoord", "cap", NULL };
  2047.  
  2048.     treport = do_flags( treport, "report", "none", rep );
  2049.     return( 0 );
  2050.   }
  2051.  
  2052.  
  2053. /*
  2054.  * set which evaluation model to use
  2055.  */
  2056. private int setmodel()
  2057.   {
  2058.     static char  *m_name[] = { "linear", "switch", NULL };
  2059.     int          new;
  2060.  
  2061.     /* note: the following will only work for 2 models! */
  2062.     new = do_flags( model_num + 1, "model", NULL, m_name ) - 1;
  2063.  
  2064.     if( new != model_num )
  2065.       {
  2066.     model_num = new;
  2067.     model = model_table[ model_num ];
  2068.     NewModel( new );
  2069.       }
  2070.     return( 0 );
  2071.   }
  2072.  
  2073.  
  2074. /*
  2075.  * set up or finish off logfile
  2076.  */
  2077. private int setlog()
  2078.   {
  2079.     if( logfile != NULL )
  2080.       {
  2081.     (void) fclose( logfile );
  2082.     logfile = NULL;
  2083.       }
  2084.  
  2085.     if( targc == 2 )
  2086.       {
  2087.     char  *mode = "w";
  2088.     char  *s = targv[1];
  2089.  
  2090.     if( *s == '+' )
  2091.       {
  2092.         s++;
  2093.         mode = "a";
  2094.       }
  2095.     if( (logfile = fopen( s, mode )) == NULL )
  2096.     error( filename, lineno, "cannot open log file %s for output\n", s );
  2097.       }
  2098.     return( 0 );
  2099.   }
  2100.  
  2101. /*
  2102.  * Helper routine for printing capacitance totals.
  2103.  */
  2104.  
  2105. private int capsummer( n )
  2106.   register nptr  n;
  2107.   {
  2108.     /* Don't UnAlias() before checking if it's an ALIAS node (PEL 5/31/93) */
  2109.     /* UnAlias( n ); */
  2110.  
  2111.     if( not (n->nflags & (MERGED | ALIAS)) )
  2112.     {
  2113.     lprintf( stdout, " %-35s\t%.3f\t%5d\t%f\t%f\n", 
  2114.         pnode( n ), 
  2115.         n->ncap, 
  2116.         n->trans, 
  2117.         n->trans*n->ncap, 
  2118.         n->trans*n->ncap / totpower);
  2119.     }
  2120.     return( 0 );
  2121.   }
  2122.  
  2123. /*
  2124.  * set up or finish off logfile
  2125.  */
  2126. private int setcaplog()
  2127.   {
  2128.     if( caplogfile != NULL )
  2129.       {
  2130.     (void) fclose( caplogfile );
  2131.     caplogfile = NULL;
  2132.     walk_net( capsummer, (char *) 0 );
  2133.       }
  2134.  
  2135.     if( targc == 2 )
  2136.       {
  2137.     char  *mode = "w";
  2138.     char  *s = targv[1];
  2139.  
  2140.     if( *s == '+' )
  2141.       {
  2142.         s++;
  2143.         mode = "a";
  2144.       }
  2145.     if( (caplogfile = fopen( s, mode )) == NULL )
  2146.     error( filename, lineno, "cannot open log file %s for output\n", s );
  2147.       }
  2148.     return( 0 );
  2149.   }
  2150.  
  2151. /*
  2152.  * Helper routine for capreport().  For a given node, print capacitive node
  2153.  * transition count.  Include node even if it is an ALIAS'd node.  Use nodal
  2154.  * 'naliases' count to distribute node capacitances equally across all
  2155.  * equivalent nodes. (PEL 5/28/93)
  2156.  */ 
  2157. private int capreportdoit( n, CapReportFile )
  2158.   register nptr  n;
  2159.   FILE *CapReportFile;
  2160.   {
  2161.     nptr  root = n;
  2162.  
  2163.     UnAlias( root );
  2164.  
  2165.     if( not (n->nflags & MERGED) )
  2166.       {
  2167.         lprintf( CapReportFile, " %-35s\t%5d\t%.3f\t%f\t%f\t%f\n", pnode( n ),
  2168.           root->naliases+1,
  2169.           root->ncap/(root->naliases+1),
  2170.           root->trans01,
  2171.           root->trans01*root->ncap/(root->naliases+1),
  2172.       powermult * (root->trans01*root->ncap/(root->naliases+1))
  2173.           );
  2174.       }
  2175.     return( 0 );
  2176.   }
  2177.  
  2178. /*
  2179.  * Print report of all capacitive node transition counts.  Report includes
  2180.  * all nodes including ALIAS'd nodes.  Capacitances are distributed equally
  2181.  * across all equivalent nodes. (PEL 5/28/93)
  2182.  */ 
  2183. private int capreport()
  2184.   {
  2185.     FILE  *CapReportFile = NULL;    /* file of effective caps. */
  2186.  
  2187.     capstoptime = d2ns(cur_delta);
  2188.     captime = capstoptime - capstarttime;
  2189.     if( captime == 0 )
  2190.       {
  2191.     lprintf( stdout, "Zero elapsed time since last zeropower\n");
  2192.     return(0);
  2193.       }
  2194.      powermult = vsupply*vsupply/captime;
  2195.  
  2196.     lprintf( stdout, 
  2197.     "%-35s\t alias\t cap.\t0->1 trans.\teffective cap. \tPd (mW)\n\n"," Node");
  2198.  
  2199.  
  2200.     if( targc == 1 )
  2201.       {
  2202.         walk_net( capreportdoit, (char *) stdout );
  2203.       }
  2204.     else
  2205.       {
  2206.         char  *mode = "w";
  2207.         char  *s = targv[1];
  2208.         if( *s == '+' )
  2209.           {
  2210.             s++;
  2211.             mode = "a";
  2212.           }
  2213.         if( (CapReportFile = fopen( s, mode )) == NULL )
  2214.               error( filename, lineno,
  2215.                  "cannot open capreport file %s for output\n", s );
  2216.         walk_net( capreportdoit, (char *) CapReportFile );
  2217.         fclose( CapReportFile );
  2218.       }
  2219.     return( 0 );
  2220.   }
  2221.  
  2222. /*
  2223.  * Helper routine to compute total capacitance charged.  For a given
  2224.  * node, computes the physical capacitance of that node weighted by the number
  2225.  * of 0->1 transitions on that node, and adds this value to the total
  2226.  * capacitance charged. (PEL 5/3/93)
  2227.  */
  2228. private int effcapsummer( n, capsum )
  2229.   register nptr  n;
  2230.   float *capsum;
  2231.   {
  2232.     char  *nname = pnode( n );
  2233.     char  *is_merge;
  2234.  
  2235.     /* Don't UnAlias() before checking if it's an ALIAS node (PEL 5/31/93) */
  2236.     /* UnAlias( n ); */
  2237.  
  2238.     if( not (n->nflags & (MERGED | ALIAS)) )
  2239.       {
  2240.     *capsum += n->trans01*n->ncap;
  2241.       }
  2242.     return( 0 );
  2243.   }
  2244.  
  2245. /*
  2246.  * Compute the total cap charged.  That is, sum the physical capacitance
  2247.  * of each node weighted by the number of 0->1 transitions on that node
  2248.  * (PEL 5/4/93)
  2249.  */
  2250. private int sumeffcap()
  2251.   {
  2252.     FILE  *CapChgdFile = NULL;    /* file of effective caps. */
  2253.     float capsum = 0;
  2254.  
  2255.     capstoptime = d2ns(cur_delta);
  2256.     captime = capstoptime - capstarttime;
  2257.     if( captime == 0 )
  2258.       {
  2259.     lprintf( stdout, "Zero elapsed time since last zeropower\n");
  2260.     return(0);
  2261.       }
  2262.      powermult = vsupply*vsupply/captime;
  2263.  
  2264.     walk_net( effcapsummer, (char *) &capsum );
  2265.     if( targc == 1 )
  2266.       {
  2267.     lprintf( stdout, "Total capacitance charged: %.4f pF\n", capsum );
  2268.     lprintf( stdout, "Elapsed time since last zeropower: %.1f ns\n", captime );
  2269.     lprintf(stdout,
  2270.      "Dynamic power estimate for traced nodes = %f (milliWatts) \n",
  2271.        capsum * powermult);
  2272.       }
  2273.     else
  2274.       {
  2275.         char  *mode = "w";
  2276.         char  *s = targv[1];
  2277.         if( *s == '+' )
  2278.           {
  2279.             s++;
  2280.             mode = "a";
  2281.           }
  2282.         if( (CapChgdFile = fopen( s, mode )) == NULL )
  2283.           error( filename, lineno, "cannot open cap file %s for output\n", s );
  2284.         fprintf( CapChgdFile, "Total capacitance charged: %f pF\n", capsum );
  2285.     lprintf( stdout, "Elapsed time since last zeropower: %f ns\n", captime );
  2286.     lprintf(stdout,
  2287.      "Dynamic power estimate for trace'd nodes = %f (milliWatts) \n",
  2288.        capsum * powermult);
  2289.         fclose( CapChgdFile );
  2290.       }
  2291.     return( 0 );
  2292.   }
  2293.  
  2294.  
  2295. /*
  2296.  * Output message to file. (PEL 10/7/93)
  2297.  */
  2298. private int dofmsg()
  2299.   {
  2300.     FILE  *MsgFile = NULL;  /* target file for message */
  2301.     int  n;
  2302.  
  2303.     char  *mode = "w";
  2304.     char  *s = targv[1];
  2305.     if( *s == '+' )
  2306.       {
  2307.         s++;
  2308.         mode = "a";
  2309.       }
  2310.     if( (MsgFile = fopen( s, mode )) == NULL )
  2311.       error( filename, lineno, "cannot open file %s for comment\n", s );
  2312.  
  2313.     for( n = 2; n < targc; n += 1 )
  2314.     fprintf( MsgFile, "%s ", targv[n] );
  2315.     fprintf( MsgFile, "\n" );
  2316.     fclose( MsgFile );
  2317.     return( 0 );
  2318.   }
  2319.  
  2320.  
  2321. /*
  2322.  * restore state of network
  2323.  */
  2324. private int do_rdstate()
  2325.   {
  2326.     char  *err;
  2327.  
  2328.     CHECK_STOP();
  2329.  
  2330.     if( err = rd_state( targv[1], (targv[0][1] == '<') ? TRUE : FALSE ) )
  2331.     error( filename, lineno, err );
  2332.     return( 0 );
  2333.   }
  2334.  
  2335.  
  2336. /*
  2337.  * restore state of network
  2338.  */
  2339. private int do_wrstate()
  2340.   {
  2341.     if( wr_state( targv[1] ) )
  2342.     error( filename, lineno, "can not write state file: %s\n", targv[1] );
  2343.     return( 0 );
  2344.   }
  2345.  
  2346.  
  2347. /*
  2348.  * set decay parameter
  2349.  */
  2350. private int setdecay()
  2351.   {
  2352.     if( targc == 1 )
  2353.       {
  2354.     if( tdecay == 0 )
  2355.         lprintf( stdout, "decay = No decay\n" );
  2356.     else
  2357.         lprintf( stdout, "decay = %.1fns\n", d2ns( tdecay ) );
  2358.       }
  2359.     else
  2360.       {
  2361.     if( (tdecay = ns2d( atof( targv[1] ) )) < 0 )
  2362.         tdecay = 0;
  2363.       }
  2364.     return( 0 );
  2365.   }
  2366.  
  2367.  
  2368. /*
  2369.  * set unitdelay parameter
  2370.  */
  2371. private int setunit()
  2372.   {
  2373.     if( targc == 1 )
  2374.       {
  2375.     if( tunitdelay == 0 )
  2376.         lprintf( stdout, "unitdelay = OFF\n" );
  2377.     else
  2378.         lprintf( stdout, "unitdelay = %.1f\n", d2ns( tunitdelay ) );
  2379.       }
  2380.     else
  2381.       {
  2382.     if( (tunitdelay = (int) ns2d( atof( targv[1] ) )) < 0 )
  2383.         tunitdelay = 0;
  2384.       }
  2385.     return( 0 );
  2386.   }
  2387.  
  2388.  
  2389. /*
  2390.  * print traceback of node's activity and that of its ancestors
  2391.  */
  2392. private void cpath( n, level )
  2393.   register nptr  n;
  2394.   int            level;
  2395.   {
  2396.     static long  ptime;        /* previous time, used during trace back */
  2397.  
  2398.     /* no last transition! */
  2399.     if( (n->nflags & MERGED) or n->t.cause == NULL )
  2400.       {
  2401.     lprintf( stdout, "  there is no previous transition!\n" );
  2402.       }
  2403.     else if( n->t.cause == inc_cause )
  2404.       {
  2405.     if( level == 0 )
  2406.         lprintf( stdout,
  2407.           "  previous transition due to incremental update\n" );
  2408.     else
  2409.         lprintf( stdout,
  2410.           "  transition of %s due to incremental update\n", pnode( n ) );
  2411.       }
  2412.     /* here if we come across a node which has changed more recently than
  2413.      * the time reached during the backtrace.  We can't continue the
  2414.      * backtrace in any reasonable fashion, so we stop here.
  2415.      */
  2416.     else if( level != 0 and n->c.time > ptime )
  2417.       {
  2418.     lprintf( stdout,
  2419.       "  transition of %s, which has since changed again\n", pnode( n ) );
  2420.       }
  2421.     /* here if there seems to be a cause for this node's transition.
  2422.      * If the node appears to have 'caused' its own transition (n->t.cause
  2423.      * == n), that means it was input.  Otherwise continue backtrace...
  2424.      */
  2425.     else if( n->t.cause == n )
  2426.       {
  2427.     lprintf( stdout, "  %s -> %c @ %.1fns , node was an input\n",
  2428.       pnode( n ), vchars[ n->npot ], d2ns( n->c.time ) );
  2429.       }
  2430.     else if( n->t.cause->nflags & VISITED )
  2431.       {
  2432.     lprintf( stdout, "  ... loop in traceback\n" );
  2433.       }
  2434.     else
  2435.       {
  2436.     long  delta_t = n->c.time - n->t.cause->c.time;
  2437.  
  2438.     n->nflags |= VISITED;
  2439.     ptime = n->c.time;
  2440.     cpath( n->t.cause, level + 1 );
  2441.     n->nflags &= ~VISITED;
  2442.     if( delta_t < 0 )
  2443.         lprintf( stdout, "  %s -> %c @ %.1fns   (??)\n", pnode( n ),
  2444.         vchars[ n->npot ], d2ns( n->c.time ) );
  2445.     else
  2446.         lprintf( stdout, "  %s -> %c @ %.1fns   (%.1fns)\n", pnode( n ),
  2447.         vchars[ n->npot ], d2ns( n->c.time ), d2ns( delta_t ) );
  2448.       }
  2449.   }
  2450.  
  2451.  
  2452. private int do_cpath( n )
  2453.   nptr  n;
  2454.   {
  2455.     lprintf( stdout, "critical path for last transition of %s:\n", pnode(n) );
  2456.     UnAlias( n );
  2457.     cpath( n, 0 );
  2458.     return( 1 );
  2459.   }
  2460.  
  2461.  
  2462. /*
  2463.  * discover and print critical path for node's last transistion
  2464.  */
  2465. private int dopath()
  2466.   {
  2467.     apply( do_cpath, NULL, (char *) 0 );
  2468.     return( 0 );
  2469.   }
  2470.  
  2471.  
  2472. #define    NBUCKETS        20    /* number of buckets in histogram */
  2473.  
  2474. typedef struct
  2475.   {
  2476.     long  begin, end, size;
  2477.     long  table[ NBUCKETS ];
  2478.   } Accounts;
  2479.  
  2480.  
  2481. /*
  2482.  * helper routine for activity command
  2483.  */
  2484. private int adoit( n, ac )
  2485.   register nptr      n;
  2486.   register Accounts  *ac;
  2487.   {
  2488.     if( not (n->nflags & (ALIAS | MERGED | POWER_RAIL)) )
  2489.       {
  2490.     if( n->c.time >= ac->begin and n->c.time <= ac->end )
  2491.         ac->table[ (n->c.time - ac->begin) / ac->size ] += 1;
  2492.       }
  2493.     return( 0 );
  2494.   }
  2495.  
  2496.  
  2497. /*
  2498.  * print histogram of circuit activity in specified time interval
  2499.  */
  2500. private int doactivity()
  2501.   {
  2502.     register int  i;
  2503.     static char   st[] = "**************************************************";
  2504.     Accounts      ac;
  2505.     long          total;
  2506.  
  2507. #   define    SIZE_ST        ( sizeof( st ) - 1 )
  2508.  
  2509.     if( targc == 2 )
  2510.       {
  2511.     ac.begin = ns2d( atof( targv[1] ) );
  2512.     ac.end = cur_delta;
  2513.       }
  2514.     else
  2515.       {
  2516.     ac.begin = ns2d( atof( targv[1] ) );
  2517.     ac.end = ns2d( atof( targv[2] ) );
  2518.       }
  2519.  
  2520.     if( ac.end < ac.begin )
  2521.     SWAP( long, ac.end, ac.begin );
  2522.  
  2523.     /* collect histogram info by walking the network */
  2524.     for( i = 0; i < NBUCKETS; ac.table[ i++ ] = 0 );
  2525.  
  2526.     ac.size = (ac.end - ac.begin + 1) / NBUCKETS;
  2527.     if( ac.size <= 0 )
  2528.     ac.size = 1;
  2529.  
  2530.     walk_net( adoit, (char *) &ac );
  2531.  
  2532.     /* print out what we found */
  2533.     for( total = i = 0; i < NBUCKETS; i++ ) total += ac.table[i];
  2534.  
  2535.     lprintf( stdout,
  2536.       "Histogram of circuit activity: %.1f -> %.1fns (bucket size = %.1f)\n",
  2537.       d2ns( ac.begin ), d2ns( ac.end ), d2ns( ac.size ) );
  2538.  
  2539.     for( i = 0; i < NBUCKETS; i += 1 )
  2540.     lprintf( stdout, " %10.1f -%10.1f%6d  %s\n",
  2541.       d2ns(ac.begin + (i * ac.size)), d2ns(ac.begin + (i + 1) * ac.size),
  2542.       ac.table[i], &st[ SIZE_ST - (SIZE_ST * ac.table[i]) / total ] );
  2543.  
  2544.     return( 0 );
  2545.   }
  2546.  
  2547.  
  2548. /*
  2549.  * Helper routine for "changes" command.
  2550.  */
  2551. private int cdoit( n, ac )
  2552.   register nptr  n;
  2553.   Accounts  *ac;
  2554.   {
  2555.     int   i;
  2556.  
  2557.     /* Don't UnAlias() before checking if it's an ALIAS node (PEL 5/31/93) */
  2558.     /* UnAlias( n ); */
  2559.  
  2560.     if( n->nflags & (MERGED | ALIAS) )
  2561.     return( 0 );
  2562.  
  2563.     if( n->c.time >= ac->begin and n->c.time <= ac->end )
  2564.       {
  2565.     i = strlen( pnode( n ) ) + 2;
  2566.     if( column + i >= MAXCOL )
  2567.       {
  2568.         lprintf( stdout, "\n" );
  2569.         column = 0;
  2570.       }
  2571.     column += i;
  2572.     lprintf( stdout, "  %s", pnode( n ) );
  2573.       }
  2574.     return( 0 );
  2575.   }
  2576.  
  2577.  
  2578. /*
  2579.  * Print list of nodes which last changed value in specified time interval
  2580.  */
  2581. private int dochanges()
  2582.   {
  2583.     Accounts  ac;
  2584.  
  2585.     if( targc == 2 )
  2586.       {
  2587.     ac.begin = ns2d( atof( targv[1] ) );
  2588.     ac.end = cur_delta;
  2589.       }
  2590.     else
  2591.       {
  2592.     ac.begin = ns2d( atof( targv[1] ) );
  2593.     ac.end = ns2d( atof( targv[2] ) );
  2594.       }
  2595.  
  2596.     column = 0;
  2597.     lprintf(stdout,"Nodes with last transition in interval %.1f -> %.1fns:\n",
  2598.       d2ns( ac.begin ), d2ns( ac.end ) );
  2599.  
  2600.     walk_net( cdoit, (char *) &ac );
  2601.     if( column != 0 )
  2602.     lprintf( stdout, "\n" );
  2603.  
  2604.     return( 0 );
  2605.   }
  2606.  
  2607.  
  2608. /*
  2609.  * Helper routine for "printx" command.
  2610.  */
  2611. private int xdoit( n, ac )
  2612.   register nptr  n;
  2613.   Accounts  *ac;
  2614.   {
  2615.     int   i;
  2616.  
  2617.     /* Don't UnAlias() before checking if it's an ALIAS node (PEL 5/31/93) */
  2618.     /* UnAlias( n ); */
  2619.  
  2620.     if( not (n->nflags & (MERGED | ALIAS)) and n->npot == X )
  2621.       {
  2622.     i = strlen( pnode( n ) ) + 2;
  2623.     if( column + i >= MAXCOL )
  2624.       {
  2625.         lprintf( stdout, "\n" );
  2626.         column = 0;
  2627.       }
  2628.     column += i;
  2629.     lprintf( stdout, "  %s", pnode( n ) );
  2630.       }
  2631.     return( 0 );
  2632.   }
  2633.  
  2634.  
  2635. /*
  2636.  * Print list of nodes with undefined (X) value
  2637.  */
  2638. private int doprintX()
  2639.   {
  2640.     lprintf( stdout, "Nodes with undefined potential:\n" );
  2641.     column = 0;
  2642.     walk_net( xdoit, (char *) 0 );
  2643.     if( column != 0 )
  2644.     lprintf( stdout, "\n" );
  2645.     return( 0 );
  2646.   }
  2647.  
  2648.  
  2649. /*
  2650.  * Helper routine for printing aliases
  2651.  */
  2652. private int aldoit( n )
  2653.   register nptr  n;
  2654.   {
  2655.     char  *nname = pnode( n );
  2656.     char  *is_merge;
  2657.  
  2658.     if( n->nflags & ALIAS )
  2659.       {
  2660.     UnAlias( n );
  2661.     is_merge = (n->nflags & MERGED) ? " (part of a stack)" : "";
  2662.     lprintf( stdout, "  %s -> %s%s\n", nname, pnode( n ), is_merge );
  2663.       }
  2664.     return( 0 );
  2665.   }
  2666.  
  2667.  
  2668. /*
  2669.  * Print nodes that are aliases
  2670.  */
  2671. private int doprintAlias()
  2672.   {
  2673.     if( naliases == 0 )
  2674.     lprintf( stdout, "there are no aliases\n" );
  2675.     else
  2676.       {
  2677.     lprintf( stdout, "there are %d aliases:\n", naliases );
  2678.     walk_net( aldoit, (char *) 0 );
  2679.       }
  2680.     return( 0 );
  2681.   }
  2682.  
  2683.  
  2684. /*
  2685.  * Helper routine to print pending events
  2686.  */
  2687. private int print_list( n, l, eolist )
  2688.   evptr  l, eolist;
  2689.   int    n;
  2690.   {
  2691.     if( l == NULL )
  2692.     return( n );
  2693.     for( eolist = eolist->flink; l != eolist and n != 0; l = l->flink, n-- )
  2694.       {
  2695.     lprintf( stdout, "Node %s -> %c @ %.1fns (%.1fns)\n",
  2696.       pnode( l->enode ), vchars[ l->eval ], d2ns( l->ntime ),
  2697.       d2ns( l->ntime - cur_delta ) );
  2698.       }
  2699.     return( n );
  2700.   }
  2701.  
  2702.  
  2703. /*
  2704.  * Print list of pending events
  2705.  */
  2706. private int printPending()
  2707.   {
  2708.     int    n;
  2709.     long   delta = 0;
  2710.     evptr  list, eolst;
  2711.  
  2712.     n = (targc == 2) ? atoi( targv[1] ) : -1;
  2713.  
  2714.     while( (delta = pending_events( delta, &list, &eolst )) and n != 0 )
  2715.         n = print_list( n, list, eolst );
  2716.     n = print_list( n, list, eolst );
  2717.     return( 0 );
  2718.   }
  2719.  
  2720.  
  2721. /*
  2722.  * set/reset various display parameters
  2723.  */
  2724. private int dodisplay()
  2725.   {
  2726.     static char    cmdfile_str[] = "cmdfile", automatic_str[] = "automatic";
  2727.     register int   i, value;
  2728.     register char  *p;
  2729.  
  2730.     if( targc == 1 )
  2731.       {
  2732.     lprintf( stdout, "display = %s%s %s%s\n",
  2733.       dcmdfile ? "" : "-", cmdfile_str,
  2734.       ddisplay ? "" : "-", automatic_str );
  2735.     return( 0 );
  2736.       }
  2737.  
  2738.     for( i = 1; i < targc; i += 1 )
  2739.       {
  2740.     p = targv[i];
  2741.     if( *p == '-' )
  2742.       {
  2743.         value = 0;
  2744.         p += 1;
  2745.       }
  2746.     else
  2747.         value = 1;
  2748.  
  2749.     if( str_eql( p, cmdfile_str ) == 0 )
  2750.         dcmdfile = value;
  2751.     else if( str_eql( p, automatic_str ) == 0 )
  2752.         ddisplay = value;
  2753.     else
  2754.         error( filename, lineno, "unrecognized display parameter: %s\n",
  2755.           targv[i] );
  2756.       }
  2757.     return( 0 );
  2758.   }
  2759.  
  2760.  
  2761. /*
  2762.  * Print list of transistors with src/drn shorted (or between power supplies).
  2763.  */
  2764. private int print_tcap()
  2765.   {
  2766.     tptr  t;
  2767.  
  2768.     if( tcap->scache.t == tcap )
  2769.     lprintf( stdout, "there are no shorted transistors\n" );
  2770.     else
  2771.     lprintf( stdout, "shorted transistors:\n" );
  2772.     for( t = tcap->scache.t; t != tcap; t = t->scache.t )
  2773.       {
  2774.     lprintf( stdout, " %s g=%s s=%s d=%s (%gx%g)\n",
  2775.       ttype[BASETYPE( t->ttype )], 
  2776.       pnode( t->gate ), pnode( t->source ), pnode( t->drain ),
  2777.       t->r->length / (double) LAMBDACM, t->r->width / (double) LAMBDACM );
  2778.       }
  2779.     return( 0 );
  2780.   }
  2781.  
  2782.  
  2783. private int set_incres()
  2784.   {
  2785.     if( targc == 1 )
  2786.     lprintf( stdout, "incremental resolution = %.1f\n", d2ns(INC_RES) );
  2787.     else
  2788.       {
  2789.     long  new_res = (long) ns2d( atof( targv[1] ) );
  2790.  
  2791.     if( new_res < 0 )
  2792.         error( filename, lineno, "resolution must be positive\n" );
  2793.     else
  2794.         INC_RES = new_res;
  2795.       }
  2796.     return( 0 );
  2797.   }
  2798.  
  2799.  
  2800. private    char    *changelog = NULL;
  2801.  
  2802.  
  2803. /*
  2804.  * set the changes-log filename. 
  2805.  */
  2806. private int setlogchanges()
  2807.   {
  2808.     Fstat  *stat;
  2809.  
  2810.     if( targc == 1 )
  2811.       {
  2812.     lprintf( stdout, "changes-logfile is %s\n",
  2813.       (changelog == NULL) ? "turned OFF" : changelog );
  2814.       }
  2815.     else
  2816.       {
  2817.     if( str_eql( "off", targv[1] ) == 0 )
  2818.       {
  2819.         if( changelog != NULL )
  2820.           {
  2821.         Vfree( changelog );
  2822.         changelog = NULL;
  2823.           }
  2824.       }
  2825.     else
  2826.       {
  2827.         stat = FileStatus( targv[1] );
  2828.         if( stat->write == 0 )
  2829.         lprintf( stdout, "can't write to file '%s'\n", targv[1] );
  2830.         else
  2831.           {
  2832.         if( stat->exist == 0 )
  2833.             lprintf( stdout, "OK, starting a new log file\n" );
  2834.         else
  2835.             lprintf( stdout,"%s already exists, will append to it\n",
  2836.               targv[1] );
  2837.         if( changelog != NULL )
  2838.             Vfree( changelog );
  2839.         changelog = Valloc( strlen( targv[1] ) + 1, 0 );
  2840.         if( changelog != NULL )
  2841.             (void) strcpy( changelog, targv[1] );
  2842.         else
  2843.             lprintf( stderr, "out of memory, logfile is OFF\n" );
  2844.           }
  2845.       }
  2846.       }
  2847.     return( 0 );
  2848.   }
  2849.  
  2850.  
  2851. /*
  2852.  * read changes and do incremental simulation.
  2853.  */
  2854. private int do_incsim()
  2855.   {
  2856.     iptr  ch_list = NULL;
  2857.  
  2858.     CHECK_STOP();
  2859.  
  2860.     if( sim_time0 != 0 )
  2861.       {
  2862.     lprintf( stderr, "Warning: part of the history was flushed:\n" );
  2863.     lprintf( stderr, "         incremental results may be wrong\n" );
  2864.       }
  2865.  
  2866.     ch_list = rd_changes( targv[1], changelog );
  2867.  
  2868.     if( ch_list == NULL )
  2869.     lprintf( stdout, "no affected nodes: done\n" );
  2870.     else
  2871.     incsim( ch_list );
  2872.     if( dodisplay )
  2873.     pnwatchlist();
  2874.     else
  2875.     prtime( 0 );
  2876.     return( 0 );
  2877.   }
  2878.  
  2879.  
  2880. private char    x_display[40];
  2881.  
  2882. private int xDisplay()
  2883.   {
  2884.     char  *s, *getenv();
  2885.  
  2886.     if( targc == 1 )
  2887.       {
  2888.     s = x_display;
  2889.     if( *s == '\0' )
  2890.         s = getenv( "DISPLAY" );
  2891.     lprintf( stdout, "DISPLAY = %s\n", (s == NULL) ? "unknown" : s );
  2892.       }
  2893.     else if( analyzerON )
  2894.     lprintf( stdout, "analyzer running, can't change display\n" );
  2895.     else
  2896.     (void) strcpy( x_display, targv[1] );
  2897.  
  2898.     return( 0 );
  2899.   }
  2900.  
  2901.  
  2902. /*
  2903.  * Startup analyzer window and/or add more signals to analyzer display list.
  2904.  */
  2905. private int analyzer()
  2906.   {
  2907.     extern int AddNode(), AddVector();
  2908.  
  2909.     if( not analyzerON )
  2910.       {
  2911.     if( not InitDisplay( first_file, (*x_display) ? x_display : NULL ) )
  2912.         return( 0 );
  2913.     InitTimes( sim_time0, stepsize, cur_delta );
  2914.       }
  2915.  
  2916.     if( targc > 1 )
  2917.       {
  2918.     int  ndigits = 0;
  2919.  
  2920.     if( targv[1][0] == '-' and targv[1][2] == '\0' )
  2921.       {
  2922.         switch( targv[1][1] )
  2923.           {
  2924.         case 'b' :    ndigits = 1;    shift_args( TRUE );    break;
  2925.         case 'o' :    ndigits = 3;    shift_args( TRUE );    break;
  2926.         case 'h' :    ndigits = 4;    shift_args( TRUE );    break;
  2927.         default : ;
  2928.           }
  2929.       }
  2930.  
  2931.     if( targc > 1 )
  2932.         apply( AddNode, AddVector, (char *) &ndigits );
  2933.       }
  2934.  
  2935.     DisplayTraces( analyzerON );        /* pass 0 first time */
  2936.  
  2937.     analyzerON = TRUE;
  2938.     return( 0 );
  2939.   }
  2940.  
  2941.  
  2942. /*
  2943.  * Clear the analyzer display list.
  2944.  */
  2945. private int clear_analyzer()
  2946.   {
  2947.     if( analyzerON )
  2948.     ClearTraces();
  2949.     else
  2950.     lprintf( stdout, "analyzer is off\n" );
  2951.     return( 0 );
  2952.   }
  2953.  
  2954.  
  2955. /*
  2956.  * Write out entire history to a file.
  2957.  */
  2958. private int dump_hist()
  2959.   {
  2960.     char  fname[ 256 ];
  2961.  
  2962.     if( first_file == NULL or cur_delta == 0 )
  2963.       {
  2964.     error( filename, lineno, "Nothing to dump\n" );
  2965.     return( 0 );
  2966.       }
  2967.  
  2968.     if( targc == 1 )
  2969.     (void) sprintf( fname, "%s.hist", first_file );
  2970.     else
  2971.     (void) strcpy( fname, targv[1] );
  2972.  
  2973.     DumpHist( fname );
  2974.  
  2975.     return( 0 );
  2976.   }
  2977.  
  2978.  
  2979. /*
  2980.  * Read network history from a file.
  2981.  */
  2982. private int do_readh()
  2983.   {
  2984.     if( analyzerON )    StopAnalyzer();
  2985.     ReadHist( targv[1] );
  2986.     if( analyzerON )    RestartAnalyzer( sim_time0, cur_delta, TRUE );
  2987.     return( 0 );
  2988.   }
  2989.  
  2990.  
  2991. /*
  2992.  * Move back simulation time to specified time.
  2993.  */
  2994. private int back_time()
  2995.   {
  2996.     long  newt;
  2997.  
  2998.     CHECK_STOP();
  2999.  
  3000.     newt = ns2d( atof( targv[1] ) );
  3001.     if( newt < sim_time0 or newt >= cur_delta )
  3002.       {
  3003.     error( filename, lineno, "%s: invalid time\n", targv[1] );
  3004.     return( 0 );
  3005.       }
  3006.     if( analyzerON )    StopAnalyzer();
  3007.  
  3008.     cur_delta = newt;
  3009.     ClearInputs();
  3010.     (void) back_sim_time( cur_delta, FALSE );
  3011.     cur_node = NULL;            /* fudge */
  3012.     walk_net( backToTime, (char *) 0 );
  3013.     if( cur_delta == 0 )
  3014.     ReInit();
  3015.  
  3016.     if( analyzerON )    RestartAnalyzer( sim_time0, cur_delta, TRUE );
  3017.  
  3018.     pnwatchlist();
  3019.     return( 0 );
  3020.   }
  3021.  
  3022.  
  3023. /*
  3024.  * Write network to file.
  3025.  */
  3026. private int wr_net()
  3027.   {
  3028.     char  fname[ 256 ];
  3029.  
  3030.     if( first_file == NULL )
  3031.       {
  3032.     error( filename, lineno, "No network?\n" );
  3033.     return( 0 );
  3034.       }
  3035.  
  3036.     if( targc == 1 )
  3037.     (void) sprintf( fname, "%s.inet", first_file );
  3038.     else
  3039.     (void) strcpy( fname, targv[1] );
  3040.  
  3041.     wr_netfile( fname );
  3042.  
  3043.     return( 0 );
  3044.   }
  3045.  
  3046.  
  3047. #ifdef STATS
  3048.  
  3049. int  ev_hgm = 0;
  3050. private    struct
  3051.   {
  3052.     hptr  head;
  3053.     hptr  tail;
  3054.   } ev_hgm_table[5];
  3055.  
  3056. void IncHistEvCnt( tp )
  3057.   int   tp;
  3058.   {
  3059.     hptr  h;
  3060.     long  tm;
  3061.     int   indx;
  3062.  
  3063.     if( ev_hgm == 0 ) return;
  3064.  
  3065.     switch( tp )
  3066.       {
  3067.     case -1:                    indx = 0;    break;
  3068.     case PUNTED:    case REVAL:    case DECAY_EV:    indx = 1;    break;
  3069.     case STIM_INP:    case STIM_XINP:    case STIMULI:    indx = 2;    break;
  3070.     case CHECK_PNT:                    indx = 3;    break;
  3071.     case XINP_EV:    case INP_EV:            indx = 4;    break;
  3072.     default :                    return;
  3073.       }
  3074.     
  3075.     tm = cur_delta / 10;
  3076.     h = ev_hgm_table[ indx ].tail;
  3077.     if( h->time == tm )
  3078.     h->t.xx += 1;
  3079.     else
  3080.       {
  3081.     if( (h = freeHist) == NULL )
  3082.         h = (hptr) MallocList( sizeof( HistEnt ), 1 );
  3083.     freeHist = h->next;
  3084.     if( ev_hgm_table[ indx ].tail == last_hist )
  3085.         ev_hgm_table[ indx ].head = h;
  3086.     else
  3087.         ev_hgm_table[ indx ].tail->next = h;
  3088.     ev_hgm_table[ indx ].tail = h;
  3089.     h->next = last_hist;
  3090.     h->time = tm;
  3091.     h->t.xx = 1;
  3092.       }
  3093.   }
  3094.  
  3095.  
  3096. private int do_ev_stats()
  3097.   {
  3098.     int   i;
  3099.  
  3100.     if( targc == 1 )
  3101.       {
  3102.     lprintf( stdout, "event recording is %s\n", (ev_hgm) ? "ON" : "OFF" );
  3103.     return( 0 );
  3104.       }
  3105.  
  3106.     if( str_eql( "on", targv[1] ) == 0 )
  3107.       {
  3108.     static int last = 5;
  3109.  
  3110.     ev_hgm = 1;
  3111.     for( i = 0; i < last; i++ )
  3112.         ev_hgm_table[i].head = ev_hgm_table[i].tail = last_hist;
  3113.     last = 0;
  3114.       }
  3115.     else if( str_eql( "clear", targv[1] ) == 0 )
  3116.       {
  3117.     for( i = 0; i < 5; i++ )
  3118.         ev_hgm_table[i].head = ev_hgm_table[i].tail = last_hist;
  3119.       }
  3120.     else if( str_eql( "off", targv[1] ) == 0 )
  3121.     ev_hgm = 0;
  3122.     else
  3123.     error( filename, lineno, "don't know what '%s' means\n", targv[1] );
  3124.  
  3125.     return( 0 );
  3126.   }
  3127.  
  3128.  
  3129. private do_pr_ev_stats()
  3130.   {
  3131.     static char *ev_name[] =
  3132.       { "evaluation", "I-evaluation", "stimulus", "check-point", "input" };
  3133.     FILE       *fp;
  3134.     int        i, lim, j;
  3135.     hptr       h;
  3136.  
  3137.     if( targc == 2 )
  3138.       {
  3139.     fp = fopen( targv[1], "w" );
  3140.     if( fp == NULL )
  3141.       {
  3142.         error( filename, lineno, "cannot open file '%s'\n", targv[1] );
  3143.         return( 0 );
  3144.       }
  3145.       }
  3146.     else if( logfile )
  3147.     fp = logfile;
  3148.     else
  3149.     fp = stdout;
  3150.  
  3151.     fprintf( fp, "Event Activity" );
  3152.  
  3153.     lim = (i_nevals != 0) ? 5 : 1;
  3154.  
  3155.     for( i = j = 0; i < lim; i++ )
  3156.       {
  3157.     h = ev_hgm_table[i].head;
  3158.     if( h == last_hist ) continue;
  3159.     j++;
  3160.     fprintf( fp, "\n** %s:\n", ev_name[i] );
  3161.     while( h != last_hist )
  3162.       {
  3163.         fprintf( fp, "%d\t%d\n", h->time, h->t.xx );
  3164.         h = h->next;
  3165.       }
  3166.     fprintf( fp, "\n" );
  3167.       }
  3168.     if( j == 0 )
  3169.       {
  3170.     fprintf( fp, ": Nothing Recorded\n" );
  3171.     if( targc == 2 ) lprintf( fp, ": Nothing Recorded\n" );
  3172.       }
  3173.     if( targc == 2 )
  3174.     fclose( fp );
  3175.     return( 0 );
  3176.   }
  3177.  
  3178. #endif STATS
  3179.  
  3180. #ifdef CL_STATS
  3181.  
  3182. private    int CLcount[ 1001 ];
  3183.  
  3184. RecordConnList( ntx )
  3185.   int             ntx;
  3186.   {
  3187.     if( ntx > 1000 ) ntx = 1000;
  3188.     CLcount[ ntx ] += 1;
  3189.   }
  3190.  
  3191. private int cl_compar( a, b )
  3192.   short  *a, *b;
  3193.   {
  3194.     return( CLcount[ *b ] - CLcount[ *a ] );
  3195.   }
  3196.  
  3197. int do_cl_stats()
  3198.   {
  3199.     short   cnt_indx[ 1001 ];
  3200.     FILE    *fp;
  3201.     int     i, ch, tot, n;
  3202.     double  avg, dev;
  3203.     extern double sqrt();
  3204.  
  3205.     if( targc == 2 )
  3206.       {
  3207.     fp = fopen( targv[1], "w" );
  3208.     if( fp == NULL )
  3209.       {
  3210.         error( filename, lineno, "cannot open file '%s'\n", targv[1] );
  3211.         return( 0 );
  3212.       }
  3213.       }
  3214.     else if( logfile )
  3215.     fp = logfile;
  3216.     else
  3217.     fp = stdout;
  3218.  
  3219.     for( avg = 0, tot = i = 0; i <= 1000; i++ )
  3220.       {
  3221.     cnt_indx[i] = i;
  3222.     if( CLcount[i] > 0 )
  3223.       {
  3224.         avg += i * CLcount[i];
  3225.         tot += CLcount[i];
  3226.       }
  3227.       }
  3228.     avg = avg / tot;
  3229.  
  3230.     for( dev = 0, i = 0; i <= 1000; i++ )
  3231.       {
  3232.     if( CLcount[i] > 0 )
  3233.         dev += CLcount[i] * (i - avg) * (i - avg);
  3234.       }
  3235.     dev = sqrt( dev / tot );
  3236.  
  3237.     qsort( cnt_indx, 1001, sizeof( short ), cl_compar );
  3238.  
  3239.     fprintf( fp, "Connection-list statistics\n" );
  3240.     fprintf( fp, "\tavg-num-trans = %.2f  std-deviation = %.2f\n", avg, dev );
  3241.  
  3242.     fprintf( fp, "num-trans  num-times      %%  %%accum\n" );
  3243.     fprintf( fp, "---------  ---------  -----  ------\n" );
  3244.     avg = tot;
  3245.     dev = 0;
  3246.     for( i = 0; i <= 1000; i++ )
  3247.       {
  3248.     double  p;
  3249.  
  3250.     n = cnt_indx[ i ];
  3251.     if( (tot = CLcount[ n ]) == 0 )
  3252.         continue;
  3253.     ch = (n == 1000) ? '>' : ' ';
  3254.     p = 100.0 * tot / avg;
  3255.     dev += p;
  3256.     fprintf( fp, "%c%8d  %9d  %5.2f  %6.2f\n", ch, n, tot, p, dev );
  3257.       }
  3258.  
  3259.     if( targc == 2 )
  3260.     fclose( fp );
  3261.     return( 0 );
  3262.   }
  3263.  
  3264. #endif CL_STATS
  3265.  
  3266.  
  3267. typedef struct
  3268.   {
  3269.     int  nsd, ng;
  3270.   } TranCnt;
  3271.  
  3272. private int count_trans( n, tt )
  3273.   nptr     n;
  3274.   TranCnt  *tt;
  3275.   {
  3276.     register lptr  l;
  3277.     register int   i;
  3278.  
  3279.     if( (n->nflags & (ALIAS | POWER_RAIL)) == 0 )
  3280.       {
  3281.     for( i = 0, l = n->ngate; l != NULL; l = l->next, i++ );
  3282.     tt->ng += i;
  3283.     for( i = 0, l = n->nterm; l != NULL; l = l->next, i++ );
  3284.     tt->nsd += i;
  3285.       }
  3286.     return( 0 );
  3287.   }
  3288.  
  3289.  
  3290. /*
  3291.  * Print event statistics.
  3292.  */
  3293. private int do_stats()
  3294.   {
  3295.     char  n1[10], n2[10];
  3296.  
  3297.     if( targc == 2 )
  3298.       {
  3299.     static TranCnt  tt = { 0, 0 };
  3300.  
  3301.     if( tt.ng == 0 and tt.nsd == 0 )
  3302.       {
  3303.         walk_net( count_trans, &tt );
  3304.         lprintf( stdout, "avg: # gates/node = %g,  # src-drn/node = %g\n",
  3305.           (double) tt.ng / nnodes, (double) tt.nsd / nnodes );
  3306.       }
  3307.       }
  3308.     lprintf( stdout, "changes = %d\n", num_edges );
  3309.     lprintf( stdout, "punts (cns) = %d (%d)\n",
  3310.       num_punted, num_cons_punted );
  3311.     if( num_punted == 0 )
  3312.       {
  3313.     (void) strcpy( n1, "0.0" );
  3314.     (void) strcpy( n2, n1 );
  3315.       }
  3316.     else
  3317.       {
  3318.     (void) sprintf( n1, "%2.2f",
  3319.       100.0 / ((float) num_edges / num_punted + 1.0) );
  3320.     (void) sprintf( n2, "%2.2f",
  3321.       (float) (num_cons_punted * 100.0 /num_punted) );
  3322.       }
  3323.     lprintf( stdout, "punts = %s%%, cons_punted = %s%%\n", n1, n2 );
  3324.  
  3325.     lprintf( stdout, "nevents = %ld; evaluations = %ld\n", nevent, nevals );
  3326.     if( i_nevals != 0 )
  3327.       {
  3328.     lprintf( stdout, "inc. evaluations = %ld; events:\n", i_nevals );
  3329.     lprintf( stdout, "reval:      %ld\n", nreval_ev );
  3330.     lprintf( stdout, "punted:     %ld\n", npunted_ev );
  3331.     lprintf( stdout, "stimuli:    %ld\n", nstimuli_ev );
  3332.     lprintf( stdout, "check pnt:  %ld\n", ncheckpt_ev );
  3333.     lprintf( stdout, "delay chk:  %ld\n", ndelaychk_ev );
  3334.     lprintf( stdout, "delay ev:   %ld\n", ndelay_ev );
  3335.       }
  3336.  
  3337.     return( 0 );
  3338.   }
  3339.  
  3340.  
  3341. /*
  3342.  * Shift the command left/right by 1.
  3343.  */
  3344. private void shift_args( left )
  3345.   int  left;
  3346.   {
  3347.     register int   ac;
  3348.     register char  **ap;
  3349.     register char  *wp;
  3350.  
  3351.     if( left )
  3352.       {
  3353.     targc--;
  3354.     for( ac = 0, ap = targv, wp = wildCard; ac < targc; ac++ )
  3355.         ap[ac] = ap[ac + 1],    wp[ac] = wp[ac + 1];
  3356.       }
  3357.     else
  3358.       {
  3359.     for( ac = targc++, ap = targv, wp = wildCard; ac >= 0; ac-- )
  3360.         ap[ac + 1] = ap[ac],    wp[ac + 1] = wp[ac];
  3361.       }
  3362.   }
  3363.  
  3364.  
  3365. /*
  3366.  * time a command and print resource utilization.
  3367.  */
  3368. private int do_time()
  3369.   {
  3370.     char  usage_str[40];
  3371.     int   narg, i = 0;
  3372.  
  3373.     shift_args( TRUE );
  3374.     narg = targc;
  3375.     if( narg )
  3376.       {
  3377.     set_usage();
  3378.     i = exec_cmd();
  3379.       }
  3380.     print_usage( narg, usage_str );    /* targc == 0 -> total usage */
  3381.     lprintf( stdout, "%s", usage_str );
  3382.     return( i );
  3383.   }
  3384.  
  3385.  
  3386. /*
  3387.  * Flush out the recorded history up to the (optional) specified time.
  3388.  */
  3389. private int flush_hist()
  3390.   {
  3391.     long  ftime;
  3392.  
  3393.     if( targc == 1 )
  3394.     ftime = cur_delta;
  3395.     else
  3396.       {
  3397.     ftime = ns2d( atof( targv[1] ) );
  3398.     if( ftime < 0 or ftime > cur_delta )
  3399.       {
  3400.         error( filename, lineno, "%s: Invalid flush time\n", targv[1] );
  3401.         return( 0 );
  3402.       }
  3403.       }
  3404.  
  3405.     if( ftime == 0 )
  3406.     return( 0 );
  3407.  
  3408.     if( analyzerON )    StopAnalyzer();
  3409.  
  3410.     FlushHist( (Ulong) ftime );
  3411.     sim_time0 = ftime;
  3412.  
  3413.     if( analyzerON )    RestartAnalyzer( sim_time0, cur_delta, TRUE );
  3414.  
  3415.     return( 0 );
  3416.   }
  3417.  
  3418.  
  3419. /*
  3420.  * Just print the string YES if transistor coordinates are avalible.
  3421.  * This is used by rsim magic interface to use transistor positions to
  3422.  * identify nodes.
  3423.  */
  3424. private int HasCoords()
  3425.   {
  3426.     if( txt_coords )
  3427.     lprintf( stdout, "YES\n" );
  3428.     return( 0 );
  3429.   }
  3430.  
  3431.  
  3432. #ifdef FAULT_SIM
  3433.  
  3434. extern    int    add_trigger();
  3435. extern    int    add_sampler();
  3436. extern    int    add_prim_output();
  3437. extern    void    cleanup_fsim();
  3438. extern    void    exec_fsim();
  3439.  
  3440.  
  3441. private int parse_trigger()
  3442.   {
  3443.     int       edge;
  3444.     long      delay;
  3445.     Find1Arg  f;
  3446.  
  3447.     if( (targc < 3 or targc > 4 ) )
  3448.     goto bad_trigger;
  3449.  
  3450.     delay = (targc > 3) ? ns2d( atof( targv[3] ) ) : 0;
  3451.  
  3452.     edge = ch2pot( targv[2][0] );
  3453.     if( edge >= N_POTS )
  3454.     return( 1 );
  3455.     if( edge != LOW and edge != HIGH )
  3456.     goto bad_trigger;
  3457.  
  3458.     FindOne( &f );
  3459.     if( f.num > 1 or f.vec != NULL )
  3460.       {
  3461.     error( filename, lineno, "%s: not a single node\n", targv[1] );
  3462.     return( 1 );
  3463.       }
  3464.     if( add_trigger( f.node, edge, delay ) )
  3465.       {
  3466.     error( filename, lineno, "trigger: %s has no %s transitions\n",
  3467.       pnode( f.node ), (edge == LOW) ? "1 -> 0" : "1 -> 0 " );
  3468.       }
  3469.     return( 0 );
  3470.  
  3471.   bad_trigger:
  3472.     error( filename, lineno, "expected: \"trigger\" node 0|1 [delay]\n");
  3473.     return( 1 );
  3474.   }
  3475.  
  3476.  
  3477. private int parse_sampler()
  3478.   {
  3479.     long  period, offset = 0;
  3480.  
  3481.     if( targc < 2 or targc > 3 )
  3482.     goto bad_sample;
  3483.  
  3484.     period = ns2d( atof( targv[1] ) );
  3485.     if( period <= 0 )
  3486.       {
  3487.     error( filename, lineno, "%s: Illegal period\n", targv[1] );
  3488.     return( 1 );
  3489.       }
  3490.     if( targc == 3 )
  3491.       {
  3492.     offset = ns2d( atof( targv[2] ) );
  3493.     if( offset < 0 )
  3494.         goto bad_sample;
  3495.       }
  3496.  
  3497.     if( cur_delta <= offset )
  3498.       {
  3499.     error( filename, lineno, "can't sample, simulation time too small\n");
  3500.     return( 1 );
  3501.       }
  3502.  
  3503.     return( add_sampler( period, offset ) );
  3504.  
  3505.   bad_sample :
  3506.     error( filename, lineno, "expected: \"sample\" period [offset]\n" );
  3507.     return( 1 );
  3508.   }
  3509.  
  3510.  
  3511. private int setup_fsim( file, p_seed )
  3512.   char  *file;
  3513.   int   *p_seed;
  3514.   {
  3515.     FILE      *fp;
  3516.     char      line[ 256 ];
  3517.     int       olineno = lineno;
  3518.     char      *ofname = filename;
  3519.     int       doing_outputs, err, percent, look_p;
  3520.  
  3521.     if( (fp = fopen( file, "r" )) == NULL )
  3522.       {
  3523.     error( filename, lineno, "cannot open '%s'\n", file );
  3524.     return( 1 );
  3525.       }
  3526.  
  3527.     filename = file;
  3528.     lineno = 0;
  3529.     err = percent = 0;
  3530.     doing_outputs = FALSE;
  3531.     look_p = TRUE;
  3532.  
  3533.     while( not err and fgetline( line, 256, fp ) != NULL )
  3534.       {
  3535.     lineno += 1;
  3536.     parse_line( line, 256 );
  3537.     if( targc == 0 )
  3538.         continue;
  3539.  
  3540.     if( look_p )    /* seed must be 1st non-empty line in file */
  3541.       {
  3542.         look_p = FALSE;
  3543.         if( str_eql( "seed", targv[0] ) == 0 )
  3544.           {
  3545.         if( targc < 2 )
  3546.           {
  3547.             error( file, lineno, "syntax: \"seed\" <percentage>\n" );
  3548.             err = 1;
  3549.           }
  3550.         else
  3551.           {
  3552.             percent = atoi( targv[1] );
  3553.             if( percent <= 0 or percent > 100 )
  3554.               {
  3555.             error( file, lineno,
  3556.               "percentage must be in the range [1-100]\n" );
  3557.             err = 1;
  3558.               }
  3559.           }
  3560.         continue;
  3561.           }
  3562.       }
  3563.  
  3564.     if( not doing_outputs )
  3565.       {
  3566.         if( str_eql( "sample", targv[0] ) == 0 )
  3567.         err = parse_sampler();
  3568.         else if( str_eql( "trigger", targv[0] ) == 0 )
  3569.         err = parse_trigger();
  3570.         else
  3571.           {
  3572.         error( file, lineno, "expected: \"trigger\" or \"sample\"\n");
  3573.         err = 1;
  3574.           }
  3575.         doing_outputs = TRUE;
  3576.       }
  3577.     else if( targc == 1 and strcmp( "***", targv[0] ) == 0 )
  3578.       {
  3579.         doing_outputs = FALSE;
  3580.       }
  3581.     else
  3582.       {
  3583.         int  any = 0;
  3584.         shift_args( FALSE );
  3585.         apply( add_prim_output, NULL, (char *) &any );
  3586.         if( any != 1 )
  3587.         err = 1;
  3588.       }
  3589.       }
  3590.  
  3591.     (void) fclose( fp );
  3592.     filename = ofname;
  3593.     lineno = olineno;
  3594.     *p_seed = percent;
  3595.     return( err );
  3596.   }
  3597.  
  3598.  
  3599. private int do_fsim()
  3600.   {
  3601.     int   p_seed;
  3602.     char  *outname;
  3603.  
  3604.     CHECK_STOP();
  3605.  
  3606.     if( cur_delta == 0 )
  3607.       {
  3608.     lprintf( stderr, "Circuit needs to be simulated before faultsim\n" );
  3609.     return( 0 );
  3610.       }
  3611.     if( sim_time0 != 0 )
  3612.       {
  3613.     lprintf( stderr, "Can't faultsim: Incomplete history\n" );
  3614.     return( 0 );
  3615.       }
  3616.  
  3617.     outname = (targc == 3) ? targv[ 2 ] : NULL;
  3618.  
  3619.     if( setup_fsim( targv[1], &p_seed ) == 0 )
  3620.     exec_fsim( outname, p_seed );
  3621.  
  3622.     cleanup_fsim();
  3623.  
  3624.     return( 0 );
  3625.   }
  3626. #endif
  3627.  
  3628.  
  3629. /* Remove path and extension from a filename */
  3630. private char *BaseName( fname )
  3631.   register char  *fname;
  3632.   {
  3633.     register char  *s = fname;
  3634.  
  3635.     while( *s )
  3636.     s++;
  3637.     while( s > fname and *s != '/' )
  3638.     s--;
  3639.     fname = ( *s == '/' ) ? s + 1 : s;
  3640.  
  3641.     for( s = fname; *s != '\0' and *s != '.'; s++ );
  3642.     *s = '\0';
  3643.     return( fname );
  3644.   }
  3645.  
  3646.  
  3647. private    int do_help();    /* forward reference */
  3648.  
  3649.  
  3650. /* list of commands and their handlers */
  3651. private Command  cmds[] = 
  3652.   {
  3653.     { "!",        quest,        2,    MAXARGS,
  3654.       "node/vector... -> info regarding node(s) gate connections"    },
  3655.     { "<",        do_rdstate,    2,    2,
  3656.       "file -> restore network state from file"                },
  3657.     { "<<",        do_rdstate,    2,    2,
  3658.       "file -> restore network and inputs state from file"        },
  3659.     { ">",        do_wrstate,    2,    2,
  3660.       "file -> write current network state to file"            },
  3661.     { "?",        quest,        2,    MAXARGS,
  3662.       "node/vector... -> info regarding node(s) src/drn connections"    },
  3663.     { "@",        cmdfile,    2,    2,
  3664.       "file -> read commands from command file"                },
  3665.     { "activity",    doactivity,    2,    3,
  3666.       "from [to] -> circuit activity in time interval"            },
  3667.     { "alias",        doprintAlias,    1,    1,
  3668.       " ->  print node aliases"                        },
  3669.     { "ana",        analyzer,    1,    MAXARGS,
  3670.       "shorthand for \"analyzer\""                    },
  3671.     { "analyzer",    analyzer,    1,    MAXARGS,
  3672.       "[-b|-o|-h] node/vector... -> display node/vector(s) in analyzer"    },
  3673.     { "assert",        doAssert,    3,    4,
  3674.       "node/vector [mask] val -> assert node/vector = val [& mask = 0]"    },
  3675.     { "back",        back_time,    2,    2,
  3676.       "time -> move simulation time back to specified to time"        },
  3677.     { "c",        doclock,    1,    2,
  3678.       "[n] -> simulate for n clock cycles (default 1)\n\
  3679.     -> or continue last simulation command prior to stoping"        },
  3680.     { "changes",    dochanges,    2,    3,
  3681.       "from [to] -> print nodes that changed in time interval"        },
  3682.     { "clear",        clear_analyzer,    1,    1,
  3683.       " -> remove all signals from analyzer window"            },
  3684.     { "clock",        setclock,    1,    MAXARGS,
  3685.       "[node/vector [val]] -> define clock sequence for node/vector"    },
  3686.     { "d",        pnlist,        1,    MAXARGS,
  3687.       "[node/vector]... -> print node/vector(s) or display-list"    },
  3688.     { "debug",        setdbg,        1,    MAXARGS,
  3689.       "[options] -> print/set debug state (? for help)"            },
  3690.     { "decay",        setdecay,    1,    2,
  3691.       "[file] -> write net history to file"                },
  3692.     { "display",    dodisplay,    1,    3,
  3693.       "[[-]option] -> print/set cmdfile and auto-watch-list display"    },
  3694.     { "dumph",        dump_hist,    1,    2,
  3695.       "[file] -> write network state history to file"            },
  3696.     { "exit",        doexit,        1,    2,
  3697.       "[status] -> exit program with given status (default: 0)"        },
  3698.     { "flush",        flush_hist,    1,    2,
  3699.       "[time] -> flush out history up to time (default:current-time)"    },
  3700.     { "h",        setvalue,    2,    MAXARGS,
  3701.       "node/vector... -> drive node/vector(s) to 1 (high)"        },
  3702.     { "has_coords",    HasCoords,    1,    1,
  3703.       " -> print if transistor coordinates are available"        },
  3704. #ifdef STATS
  3705.     { "histev",        do_ev_stats,    1,    2,
  3706.       "[clear | off | on] -> enable/disable/clear event activity record"},
  3707.     { "evstats",    do_pr_ev_stats,    1,    2,
  3708.       "[file] -> print event activity recorded"                },
  3709. #endif STATS
  3710. #ifdef CL_STATS
  3711.     { "clstats",    do_cl_stats,    1,    2,
  3712.       "[file] -> print connection-list statistics"            },
  3713. #endif CL_STATS
  3714.     { "help",        do_help,    1,    MAXARGS,
  3715.       "[command]... -> print info on command(s) or available commands"    },
  3716.     { "inputs",        inputs,        1,    1,
  3717.       " -> print currently driven (input) nodes"            },
  3718.     { "ires",        set_incres,    1,    2,
  3719.       "[time] -> print/set incremental resolution to time"        },
  3720.     { "isim",        do_incsim,    2,    2,
  3721.       "[file] -> read changes from file and incrementally resimulate"    },
  3722.     { "l",        setvalue,    2,    MAXARGS,
  3723.       "node/vector... -> drive node/vector(s) to 0 (low)"        },
  3724.     { "logfile",    setlog,        1,    2,
  3725.       "[[+]file] -> start/stop log file (+file appends to file)"    },
  3726.     { "model",        setmodel,    1,    2,
  3727.       "[linear|switch] -> print/change simulation model"        },
  3728.     { "p",        dophase,    1,    1,
  3729.       "step clock one simulation step (phase)"                },
  3730.     { "path",        dopath,        2,    MAXARGS,
  3731.       "node/vector... -> critical path for last transition of node(s)"    },
  3732.     { "print",        domsg,        1,    MAXARGS,
  3733.       "[text...] -> print specified text"                },
  3734.     { "printp",        printPending,    1,    2,
  3735.       "[n] -> print up to 'n' pending events (default: all)"        },
  3736.     { "printx",        doprintX,    1,    1,
  3737.       " -> print all undefined (X) nodes"                },
  3738.     { "q",        quit,        1,    1,
  3739.       " -> terminate input from current stream"                },
  3740.     { "R",        runseq,        1,    2,
  3741.       "[n] -> simulate for 'n' cycles (default: longest sequence)"    },
  3742.     { "readh",        do_readh,    2,    2,
  3743.       "file -> read network state history from file"            },
  3744.     { "report",        setreport,    1,    10,
  3745.       "[args] -> print/set trace-info or decay report (? for help)"    },
  3746.     { "s",        dostep,        1,    2,
  3747.       "[time] -> simulate for specified time (default: stepsize)"    },
  3748.     { "set",        setvector,    3,    3,
  3749.       "vector value -> assign value to vector"                },
  3750.     { "setlog",        setlogchanges,    1,    2,
  3751.       "[file|off] -> print/change net-changes log-filename"        },
  3752.     { "setpath",    docmdpath,    1,    MAXARGS,
  3753.       "[[+] path]... -> print/set/add-to cmd files search path"        },
  3754.     { "stats",        do_stats,    1,    2,
  3755.       " -> print event statistics"                    },
  3756.     { "stepsize",    setstep,    1,    2,
  3757.       "[time] -> print/set simulation step size"            },
  3758.     { "stop",        setstop,    2,    MAXARGS,
  3759.       "[-]node/vector... -> pause simulation when node/vector(s) change"},
  3760.     { "t",        settrace,    2,    MAXARGS,
  3761.       "[-]node/vector... -> start/stop tracing specified node/vector(s)"},
  3762.     { "tcap",        print_tcap,    1,    1,
  3763.       " -> print all shorted transistors"                },
  3764.     { "time",        do_time,    1,    MAXARGS,
  3765.       "[command...] -> time given command or program"            },
  3766.     { "u",        setvalue,    2,    MAXARGS,
  3767.       "[node/vector]... -> drive a node/vector(s) to X (undefined)"    },
  3768.     { "unitdelay",    setunit,    1,    2,
  3769.       "[time] -> force transitions to specified time (0 to disable)"    },
  3770.     { "V",        setseq,        1,    MAXARGS,
  3771.       "[node/vector [val...]] -> define input sequence for node/vector"    },
  3772.     { "vector",        dovector,    3,    MAXARGS,
  3773.       "name node... -> (re)define vector 'name' composed of node(s)"    },
  3774.     { "w",        display,    2,    MAXARGS,
  3775.       "[-]node/vector... -> add/delete node/vector(s) to display-list"    },
  3776.     { "wnet",        wr_net,        1,    MAXARGS,
  3777.       "[file] -> write network to file (smaller/faster than sim file)"    },
  3778.     { "x",        setvalue,    2,    MAXARGS,
  3779.       "node/vector... -> make node/vector(s) undriven (non-input)"    },
  3780.     { "Xdisplay",    xDisplay,    1,    2,
  3781.       "[Xserver] -> print/set X display (for analyzer)"            },
  3782. #ifdef FAULT_SIM
  3783.     { "faultsim",    do_fsim,    2,    3,
  3784.       "infile [outfile] -> do stuck-at fault simulation"        },
  3785. #endif
  3786.     { "caplogfile",    setcaplog,    1,    2,
  3787.       "[[+]file] -> start/stop cap logfile (+file appends to file)"    },
  3788.     { "captrace",    setcaptrace,    2,    MAXARGS,
  3789.       "[-]node/vector... -> start/stop cap tracing specified node/vector(s)"},
  3790.     { "sumcap",        sumcap,        1,    2,
  3791.       "print out sum of capacitances of all nodes"            },
  3792.     { "vsupply",    setvsupply,    1,    2,
  3793.       "[v] Set supply voltage = v Volts (no arguments displays value)"    },
  3794.     { "zeropower",    zeropower,    1,    1,    /* (PEL 4/30/93) */
  3795.       " -> zero current power estimate and nodal transition counts"    },
  3796.     { "sumeffcap",    sumeffcap,    1,    2,    /* (PEL 5/4/93) */
  3797.       "[[+]file] -> output total effective capacitance charged from 0->1"},
  3798.     { "inputcap",    setinputcap,    1,    2,    /* (PEL 5/4/93) */
  3799.       "[on | off] -> enable/disable cap. contribs. from transitions on inputs"},
  3800.     { "capreport",    capreport,    1,    2,    /* (PEL 5/28/93) */
  3801.       "[[+]file] -> report cap. node trans. distributed over all node aliases"},
  3802.     { "fprint",        dofmsg,        2,    MAXARGS, /* (PEL 10/7/93) */
  3803.       "[+]file [text...] -> output specified text to file"},
  3804.     { NULL,        NULL,        0,    0,    NULL        }
  3805.   };
  3806.  
  3807.  
  3808. private int do_help()
  3809.   {
  3810.     Command  *c;
  3811.     int      n, i, col = 0;
  3812.  
  3813.     if( targc == 1 )
  3814.       {
  3815.     lprintf( stdout, "available commands:\n" );
  3816.     for( c = cmds; c->name != NULL; c++ )
  3817.       {
  3818.         i = strlen( c->name ) + 1;
  3819.         if( col + i >= MAXCOL )
  3820.           {
  3821.         lprintf( stdout, "\n" );
  3822.         col = 0;
  3823.           }
  3824.         col += i;
  3825.         lprintf( stdout, " %s", c->name );
  3826.       }
  3827.     lprintf( stdout, "\n" );
  3828.       }
  3829.     else
  3830.       {
  3831.     for( i = 1; i < targc; i++ )
  3832.       {
  3833.         for( c = cmdtbl[ HashCmd( targv[i] ) ]; c != NULL; c = c->next )
  3834.           {
  3835.         if( strcmp( targv[i], c->name ) == 0 )
  3836.             break;
  3837.           }
  3838.         if( c )
  3839.         lprintf( stdout, "%s %s\n", c->name, c->help );
  3840.         else
  3841.         lprintf( stdout, "%s -> UNKNOWN\n", targv[i] );
  3842.       }
  3843.       }
  3844.     return( 0 );
  3845.   }
  3846.  
  3847.  
  3848. /* VARARGS1 */
  3849. private void Usage( msg, s1 )
  3850.   char  *msg, *s1;
  3851.   {
  3852.     (void) fprintf( stderr, msg, s1 );
  3853.     (void) fprintf( stderr, "usage:\n irsim " );
  3854.     (void) fprintf( stderr,"[-s] prm_file {sim_file ..} [-cmd_file ..]\n" );
  3855.     (void) fprintf( stderr, "\t-s\t\tstack series transistors\n" );
  3856.     (void) fprintf( stderr, "\tprm_file\telectrical parameters file\n" );
  3857.     (void) fprintf( stderr, "\tsim_file\tsim (network) file[s]\n" );
  3858.     (void) fprintf( stderr, "\tcmd_file\texecute command file[s]\n" );
  3859.     exit( 1 );
  3860.   }
  3861.  
  3862.  
  3863. private int cmd_cmp( a, b )
  3864.   Command *a, *b;
  3865.   {
  3866.     return( str_eql( a->name, b->name ) );
  3867.   }
  3868.  
  3869.  
  3870. private void init_commands()
  3871.   {
  3872.     register int      n;
  3873.     register Command  *c;
  3874.  
  3875.     n = sizeof( cmds ) / sizeof( Command ) - 1;
  3876.     qsort( cmds, n, sizeof( Command ), cmd_cmp );
  3877.  
  3878.     for( n = 0; n < CMDTBLSIZE; n++ )
  3879.     cmdtbl[n] = NULL;
  3880.     for( c = cmds; c->name != NULL; c += 1 )    
  3881.       {
  3882.     n = HashCmd( c->name );
  3883.     c->next = cmdtbl[ n ];
  3884.     cmdtbl[ n ] = c;
  3885.       }
  3886.   }
  3887.  
  3888.  
  3889. public main( argc, argv )
  3890.    char *argv[];
  3891.   {
  3892.     int  i, arg1;
  3893.  
  3894.     InitSignals();
  3895.     InitUsage();
  3896.     InitThevs();
  3897.     InitCAD();
  3898.     InitCmdPath();
  3899.     init_hist();
  3900.     (void) fprintf( stdout, "*** IRSIM-CAP %s ***\n", version );
  3901.     (void) fflush( stdout );
  3902.  
  3903.     filename = "*initialization*";
  3904.  
  3905.     for( arg1 = 1; arg1 < argc; arg1++ )
  3906.       {
  3907.     if( argv[arg1][0] == '-' )
  3908.       {
  3909.         switch( argv[arg1][1] )
  3910.           {
  3911.         case 's' :            /* stack series transistors */
  3912.             stack_txtors = TRUE;
  3913.             break;
  3914.         default :
  3915.             Usage( "unknown switch: %s\n", argv[arg1] );
  3916.           }
  3917.       }
  3918.     else
  3919.       break;
  3920.       }
  3921.  
  3922.     /* read in the electrical configuration file */
  3923.     if( arg1 < argc )
  3924.     config( argv[arg1++] );
  3925.     else
  3926.     Usage( "No electrical parameters file specified. Bye\n" );
  3927.  
  3928.  
  3929.     /* Read network files (sim files) */
  3930.     for( i = arg1; i < argc; i += 1 )
  3931.       {
  3932.     if( argv[i][0] != '-' and argv[i][0] != '+' )
  3933.       {
  3934.         rd_network( argv[i] );
  3935.         if( first_file == NULL )
  3936.         first_file = BaseName( argv[i] );
  3937.       }
  3938.       }
  3939.  
  3940.     if( first_file == NULL )
  3941.       {
  3942.     (void) fprintf( stderr, "No network, no work. Bye...\n" );
  3943.     exit( 1 );
  3944.       }
  3945.  
  3946.     ConnectNetwork();    /* connect all txtors to corresponding nodes */
  3947.  
  3948.     init_commands();    /* set up command table */
  3949.  
  3950.     init_event();
  3951.  
  3952.     /* search for -filename for command files to process. */
  3953.     filename = "command line";
  3954.     lineno = 1;
  3955.     for( i = arg1; i < argc; i++ )
  3956.     if( argv[i][0] == '-' and not finput( &argv[i][1] ) )
  3957.         error( filename, lineno, "cannot open %s for input\n",
  3958.            &argv[i][1] );
  3959.  
  3960.     /* finally (assuming we get this far) read commands from user */
  3961.     debug = 0;
  3962.     filename = "tty";
  3963.     lineno = 0;
  3964.     (void) input( stdin );
  3965.  
  3966.     TerminateAnalyzer();
  3967.     exit( 0 );
  3968.     /* NOTREACHED */
  3969.   }
  3970.  
  3971.